1<!DOCTYPE html><html lang="en" class="w-full overflow-x-hidden"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="image" href="https://brand-assets.pressbox.studio/019f1fa9-7312-769c-9379-df96b5b0d60d.png"/><link rel="preload" as="image" href="https://licensed-images.pressbox.studio/pressbox/self-licensed/1775049890710.webp?width=800&format=auto&org=pressbox"/><link rel="preload" as="image" href="https://brand-assets.pressbox.studio/019dafe6-a82b-788a-9735-628e20429017.png"/><link rel="preload" as="image" href="https://licensed-images.pressbox.studio/pressbox/self-licensed/1775049890710.webp?org=pressbox"/><link rel="preload" as="image" href="https://brand-assets.pressbox.studio/019d2531-7c5f-7991-a491-4f136ea780d1.webp"/><link rel="preload" as="image" href="https://brand-assets.pressbox.studio/019d1606-9b5f-7cc9-a193-0d71bfd6252b.webp"/><link rel="preload" as="image" href="https://brand-assets.pressbox.studio/019d1603-f108-7999-94e1-1ba4bf2e2243.webp"/><link rel="preload" as="image" href="https://brand-assets.pressbox.studio/019d1606-33ea-7999-94e1-35898d83fab4.webp"/><link rel="preload" as="image" href="https://brand-assets.pressbox.studio/019d1605-f5e8-7999-94e1-29aa26e8bba6.webp"/><link rel="preload" as="image" href="https://brand-assets.pressbox.studio/019d1603-c438-7999-94e1-14bd569d61db.webp"/><link rel="preload" as="image" href="/images/icons/[email protected]"/><link rel="modulepreload" href="/assets/entry.client-BwKJ4h79.js"/><link rel="modulepreload" href="/assets/rolldown-runtime-CNC7AqOf.js"/><link rel="modulepreload" href="/assets/exports-CpC8xO3z.js"/><link rel="modulepreload" href="/assets/chunk-62JRHF6Z-b62IZc0S.js"/><link rel="modulepreload" href="/assets/react-dom-Bn-YL-V5.js"/><link rel="modulepreload" href="/assets/jsx-runtime-DiK4U9sA.js"/><link rel="modulepreload" href="/assets/root-mHGU7cF1.js"/><link rel="modulepreload" href="/assets/blog._index-BuUKgbUM.js"/><link rel="modulepreload" href="/assets/Header-BI_BP9KD.js"/><link rel="modulepreload" href="/assets/Footer-CkgdE3gs.js"/><link rel="modulepreload" href="/assets/SubHeading-CGDbwfzf.js"/><link rel="modulepreload" href="/assets/TitleHeading-BX1pHKUv.js"/><link rel="modulepreload" href="/assets/CTABanner-DsPF4iVS.js"/><link rel="modulepreload" href="/assets/blog-utils-B-ecIOuG.js"/><title>From the PressBox â The Future of Personalized Media</title><meta name="description" content="The future of media & entertainment should be in the hands of fans. Read more on how PressBox is building the future of personalization."/><meta name="title" property="og:title" content="From the PressBox â The Future of Personalized Media"/><meta property="og:type" content="website"/><meta property="og:image" content="https://pressbox.studio/images/icons/logo_square_on_white.webp"/><meta property="og:url" content="https://pressbox.studio/blog"/><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous"/><link rel="preconnect" href="https://use.typekit.net"/><link rel="icon" href="/favicon.png" type="image/png"/><link rel="apple-touch-icon" href="/images/icons/logo_square_on_white.webp" type="image/png"/><link rel="stylesheet" href="/assets/root-Bpjm4FGr.css"/><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Knewave&display=block"/><link rel="stylesheet" href="https://use.typekit.net/gyf6wws.css"/></head><body class="w-full overflow-x-hidden"><div class="relative flex w-full flex-col overflow-hidden bg-off-white"><div class="pointer-events-none fixed inset-0 z-[-1]" style="background-image:linear-gradient( 85.6deg, rgba(112,246,255,0.11) 11.2%, rgba(221,108,241,0.06) 42%, rgba(229,106,253,0.12) 71.5%, rgba(123,183,253,.20) 100.2% )"></div><div class="relative"><header class="fixed top-4 left-1/2 z-[100] w-full max-w-[1440px] -translate-x-1/2 px-4 sm:top-8 sm:px-8 xl:px-[85px]"><div class="overflow-hidden rounded-[15px] border-[4px] border-black shadow-drop-lg" data-nav-bar="true" style="background:rgba(209, 213, 219, 0.75);backdrop-filter:blur(5px)"><div class="flex items-center justify-between"><div class="-mt-[4px] -mb-[4px] -ml-[4px] border-black border-r-[4px] bg-gradient-charcoal px-3 py-[1.27rem] sm:px-6 xl:mr-8"><a class="block" aria-label="PressBox Home" href="/" data-discover="true"><div style="filter:drop-shadow(3px 0 0 black) drop-shadow(-3px 0 0 black) drop-shadow(0 3px 0 black) drop-shadow(0 -3px 0 black)"><svg viewBox="0 0 142 26" xmlns="http://www.w3.org/2000/svg" class="w-[100px] lg:w-[153px]" role="img" aria-label="PressBox"><path d="M4.356 1.024H11.484C16.308 1.024 18.18 3.508 18.18 7.036C18.18 8.98 17.64 11.716 16.776 13.444C15.588 15.82 13.356 17.116 9.18 17.116H7.272L5.868 25H0.144L4.356 1.024ZM9.288 5.596L8.1 12.544H9.324C10.62 12.544 11.376 12.04 11.772 11.248C12.204 10.42 12.528 8.404 12.528 7.54C12.528 6.28 11.844 5.596 10.404 5.596H9.288ZM24.7815 16.576L23.3055 25H17.5815L21.7935 1.024H28.7775C33.7815 1.024 35.8695 3.076 35.8695 6.784C35.8695 8.728 35.4375 11.284 34.6455 12.868C33.9975 14.2 32.8815 15.136 31.4775 15.748L33.3135 25H27.5175L25.9695 16.576H24.7815ZM26.7255 5.632L25.6095 12.112H26.9055C28.2015 12.112 29.0295 11.572 29.4255 10.78C29.7855 10.06 30.0735 8.836 30.0735 7.648C30.0735 6.244 29.5335 5.632 27.3735 5.632H26.7255ZM40.0044 1.024H53.1084L52.2084 6.244H44.7204L44.0004 10.276H49.6884L48.7884 15.316H43.1004L42.3444 19.78H49.8324L48.8964 25H35.7924L40.0044 1.024ZM62.2637 0.52C67.0517 0.52 69.4277 3.004 69.4277 6.64C69.4277 7.324 69.3197 8.188 69.2117 8.98L63.9917 9.124C64.0997 8.368 64.1717 7.828 64.1717 7.252C64.1717 5.812 63.4157 5.128 62.1557 5.128C60.7877 5.128 59.9957 5.992 59.9957 7.252C59.9957 8.332 60.6437 9.232 63.3797 11.356C66.4037 13.696 67.4477 15.46 67.4477 17.908C67.4477 21.94 65.2157 25.504 59.1677 25.504C54.2357 25.504 51.9677 23.092 51.9677 19.276C51.9677 18.484 52.0757 17.512 52.2917 16.576L57.6197 16.432C57.4397 17.188 57.3677 17.836 57.3677 18.448C57.3677 20.104 58.3037 20.752 59.5997 20.752C61.0397 20.752 61.8317 19.888 61.8317 18.52C61.8317 17.368 61.1117 16.468 58.5917 14.524C55.6037 12.22 54.4517 10.636 54.4517 7.972C54.4517 4.012 56.7917 0.52 62.2637 0.52ZM79.209 0.52C83.997 0.52 86.373 3.004 86.373 6.64C86.373 7.324 86.265 8.188 86.157 8.98L80.937 9.124C81.045 8.368 81.117 7.828 81.117 7.252C81.117 5.812 80.361 5.128 79.101 5.128C77.733 5.128 76.941 5.992 76.941 7.252C76.941 8.332 77.589 9.232 80.325 11.356C83.349 13.696 84.393 15.46 84.393 17.908C84.393 21.94 82.161 25.504 76.113 25.504C71.181 25.504 68.913 23.092
168.913 19.276C68.913 18.484 69.021 17.512 69.237 16.576L74.565 16.432C74.385 17.188 74.313 17.836 74.313 18.448C74.313 20.104 75.249 20.752 76.545 20.752C77.985 20.752 78.777 19.888 78.777 18.52C78.777 17.368 78.057 16.468 75.537 14.524C72.549 12.22 71.397 10.636 71.397 7.972C71.397 4.012 73.737 0.52 79.209 0.52ZM89.9263 1.024H97.6663C101.734 1.024 103.786 3.004 103.786 6.208C103.786 7.54 103.534 9.16 102.994 10.204C102.346 11.5 101.158 12.4 99.2503 12.868V12.94C101.158 13.444 102.238 14.776 102.238 17.08C102.238 18.412 101.914 20.284 101.194 21.724C100.006 24.064 97.5583 25 94.3903 25H85.7143L89.9263 1.024ZM94.6423 5.596L93.7063 10.996H95.4343C96.5863 10.996 97.3423 10.6 97.7743 9.736C98.0623 9.124 98.2423 8.08 98.2423 7.288C98.2423 6.208 97.5943 5.596 96.2623 5.596H94.6423ZM93.0223 14.812L92.0503 20.428H93.9583C95.1823 20.428 95.7583 20.032 96.1543 19.276C96.5143 18.556 96.6943 17.404 96.6943 16.612C96.6943 15.532 96.1183 14.812 94.7143 14.812H93.0223ZM114.912 0.52C118.944 0.52 122.292 2.5 122.292 7.18C122.292 9.7 120.816 18.376 119.448 21.256C118.044 24.208 115.164 25.504 111.96 25.504C107.928 25.504 104.58 23.524 104.58 18.844C104.58 16.324 106.056 7.648 107.424 4.768C108.828 1.816 111.708 0.52 114.912 0.52ZM114.624 5.452C113.688 5.452 112.968 5.848 112.464 6.892C111.636 8.548 110.196 16.684 110.196 18.52C110.196 20.032 111.132 20.572 112.248 20.572C113.184 20.572 113.904 20.176 114.408 19.132C115.236 17.476 116.676 9.34 116.676 7.504C116.676 5.992 115.74 5.452 114.624 5.452ZM132.152 25L130.352 17.404L126.176 25H120.2L127.94 12.256L124.736 1.024H130.604L132.188 8.116L135.968 1.024H141.944L134.564 13.408L138.02 25H132.152Z" fill="#FFFFFF"></path></svg></div></a></div><nav class="hidden flex-1 items-center justify-evenly md:flex xl:justify-start xl:gap-8"><div class="relative flex h-full items-center"><button type="button" class="group relative -mb-[5px] px-6 pt-4 pb-[21px] font-bold font-roc-grotesk text-[18px] text-charcoal transition-all duration-300 hover:scale-110 hover:text-black lg:px-11 lg:text-[22px] xl:px-4" style="transform:scale(1) rotate(0deg);transition:transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)"><span class="absolute transition-all duration-300" style="background:linear-gradient(90deg, hsl(79, 100%, 70%) 0%, hsl(179, 72%, 51%) 100%);opacity:0.55;transform:rotate(-1.2deg) skewX(-0.5deg) translateY(-50%) scaleX(0.9);transform-origin:center;top:50%;left:-10px;right:-10px;height:37%;border-radius:2px 1px 3px 0px;pointer-events:none;z-index:0;mix-blend-mode:multiply"></span><span class="absolute transition-all duration-300" style="background:linear-gradient(90deg, hsl(79, 100%, 70%) 0%, hsl(179, 72%, 51%) 100%);opacity:0.315;transform:rotate(0.5deg) skewX(-1deg) translateY(-50%) scaleX(0.9);transform-origin:center;top:48%;left:-12px;width:15%;height:32%;border-radius:1px 0px 2px 1px;filter:blur(1.5px);pointer-events:none;z-index:0;mix-blend-mode:multiply"></span><span class="relative z-10">Solutions</span></button></div><div class="h-[20px] w-[1px] bg-gray-600 opacity-70"></div><div class="relative flex h-full items-center"><button type="button" class="group relative -mb-[5px] px-6 pt-4 pb-[21px] font-bold font-roc-grotesk text-[18px] text-charcoal transition-all duration-300 hover:scale-110 hover:text-black lg:px-11 lg:text-[22px] xl:px-4" style="transform:scale(1) rotate(0deg);transition:transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)"><span class="absolute transition-all duration-300" style="background:linear-gradient(90deg, hsl(256, 73%, 72%) 0%, hsl(342, 80%, 66%) 100%);opacity:0.55;transform:rotate(-1.2deg) skewX(-0.5deg) translateY(-50%) scaleX(0.9);transform-origin:center;top:50%;left:-10px;right:-10px;height:37%;border-radius:2px 1px 3px 0px;pointer-events:none;z-index:0;mix-blend-mode:multiply"></span><span class="absolute transition-all duration-300" style="background:linear-gradient(90deg, hsl(256, 73%, 72%) 0%, hsl(342, 80%, 66%) 100%);opacity:0.315;transform:rotate(0.5deg) skewX(-1deg) translateY(-50%) scaleX(0.9);transform-origin:center;top:48%;left:-12px;width:15%;height:32%;border-radius:1px 0px 2px 1px;filter:blur(1.5px);pointer-events:none;z-index:0;mix-blend-mode:multiply"></span><span class="relative z-10">Company</span></button></div></nav><div class="mx-4 hidden h-[20px] w-[1px] bg-gray-600 opacity-70 lg:block"></div><div class="z-10 hidden items-center gap-3 px-[24px] md:inline-flex xl:ml-auto"><div class="relative inline-block mt-1" style="transform:scale(1);transition:transform 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94)"><div class="absolute -inset-y-1 -inset-x-1 pointer-events-none" style="transform:scale(1);transition:transform 0.3s ease-out;z-index:-1"><div class="absolute inset-0 rounded-lg bg-gradient-glow-light-small" style="filter:blur(4px) brightness(1);opacity:0.51;transition:filter 0.3s ease-out, opacity 0.3s ease-out;animation:pulse 9s ease-in-out infinite"></div></div><div class="relative inline-block cursor-pointer" role="presentation"><div class="absolute inset-0 rounded-lg" style="background:linear-gradient(135deg, rgb(2
16, 26, 26) 0%, rgb(0, 0, 0) 100%)"></div><div class="pointer-events-none absolute inset-0 rounded-lg" style="background:black;mask-image:linear-gradient(transparent, transparent);-webkit-mask-image:linear-gradient(transparent, transparent);transition:mask-image 0.6s ease, -webkit-mask-image 0.6s ease"></div><a href="https://app.pressbox.studio" target="_blank" rel="noopener noreferrer" class="relative block px-[16px] py-[4px] rounded-md font-black font-proxima-nova-condensed text-gray-200 text-[18px] lg:text-[22px] z-10 overflow-hidden capitalize transition-all" style="margin:3px;border-radius:5px;-webkit-text-stroke:3px hsl(0, 0%, 92%);paint-order:stroke fill;text-shadow:1px 1px 2px rgba(0,0,0,0.3);box-shadow:3px 3px 0px rgba(0,0,0,0.25);transition:box-shadow 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94), -webkit-text-stroke 0.6s ease" role="button" aria-label="Login"><div class="pointer-events-none absolute inset-0 bg-gradient-button-light"></div><div class="pointer-events-none absolute inset-0 bg-gradient-button-dark" style="mask-image:linear-gradient(transparent, transparent);-webkit-mask-image:linear-gradient(transparent, transparent);transition:mask-image 0.6s ease, -webkit-mask-image 0.6s ease"></div><span class="relative z-10 inline-block text-charcoal">Login</span></a></div><style> 2 @keyframes pulse { 3 0%, 100% { 4 opacity: 0.26; 5 transform: scale(1); 6 } 7 50% { 8 opacity: 0.3; 9 transform: scale(1.04); 10 } 11 } 12 </style></div><div class="relative inline-block mt-1" style="transform:scale(1);transition:transform 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94)"><div class="absolute -inset-y-1 -inset-x-1 pointer-events-none" style="transform:scale(1);transition:transform 0.3s ease-out;z-index:-1"><div class="absolute inset-0 rounded-lg bg-gradient-glow-hitman-small" style="filter:blur(4px) brightness(1);opacity:0.51;transition:filter 0.3s ease-out, opacity 0.3s ease-out;animation:pulse 9s ease-in-out infinite"></div></div><div class="relative inline-block cursor-pointer" role="presentation"><div class="absolute inset-0 rounded-lg" style="background:linear-gradient(135deg, hsl(345, 100%, 40%) 0%, hsl(342, 80%, 30%) 100%)"></div><div class="pointer-events-none absolute inset-0 rounded-lg" style="background:black;mask-image:linear-gradient(transparent, transparent);-webkit-mask-image:linear-gradient(transparent, transparent);transition:mask-image 0.6s ease, -webkit-mask-image 0.6s ease"></div><a href="https://cal.com/brian-hough-pressbox/demo" target="_blank" rel="noopener noreferrer" class="relative block px-[16px] py-[4px] rounded-md font-black font-proxima-nova-condensed text-gray-200 text-[18px] lg:text-[22px] z-10 overflow-hidden capitalize transition-all" style="margin:3px;border-radius:5px;-webkit-text-stroke:3px black;paint-order:stroke fill;text-shadow:1px 1px 2px rgba(0,0,0,0.3);box-shadow:3px 3px 0px rgba(0,0,0,0.25);transition:box-shadow 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94), -webkit-text-stroke 0.6s ease" role="button" aria-label="Demo"><div class="pointer-events-none absolute inset-0 bg-gradient-button-hitman"></div><div class="pointer-events-none absolute inset-0 bg-gradient-button-dark" style="mask-image:linear-gradient(transparent, transparent);-webkit-mask-image:linear-gradient(transparent, transparent);transition:mask-image 0.6s ease, -webkit-mask-image 0.6s ease"></div><span class="relative z-10 inline-block text-pink-100">Demo</span></a></div><style> 13 @keyframes pulse { 14 0%, 100% { 15 opacity: 0.26; 16 transform: scale(1); 17 } 18 50% { 19 opacity: 0.3; 20 transform: scale(1.04); 21 } 22 } 23 </style></div></div><button type="button" class="mr-2 p-2 md:hidden" aria-label="Toggle menu"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-menu h-6 w-6 text-black"><line x1="4" x2="20" y1="12" y2="12"></line><line x1="4" x2="20" y1="6" y2="6"></line><line x1="4" x2="20" y1="18" y2="18"></line></svg></button></div></div></header><section class="mt-[180px] mb-[40px] flex flex-col items-center justify-center px-4 text-center sm:mt-[220px] sm:mb-[48px] md:mt-[240px] md:mb-[56px]"><div class="relative flex w-full max-w-[850px] flex-col items-center"><div class="relative flex origin-center scale-[0.85] items-center justify-center sm:scale-[0.97] md:scale-100"><div class="absolute top-[-30px] sm:top-[-40px] md:top-[-50px] lg:top-[-60px]" style="z-index:0;transform:rotate(-1.5deg);pointer-events:none"><span class="font-knewave text-[60px] sm:text-[90px] md:text-[120px] lg:text-[155px] xl:text-[190px] uppercase inline-block relative" style="transform-origin:center bottom;transform:perspective(500px) rotateX(-8deg);color:rgba(255, 255, 255, 0.9)"><span class="absolute z-10" style="top:calc(50% + 2px);left:-8%;width:116%;height:67.5%;border-radius:8px 12px 10px 6px;filter:blur(0.5px);background:linear-gradient(95deg, rgba(255, 82, 126, 0.15) 0%, rgba(255, 165, 0, 0.15) 100%);
23transform:translateY(-50%) rotate(-2deg) skewX(-3deg) skewY(2deg) scaleX(0);transform-origin:left center;transition:transform 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94)"></span><span class="absolute z-10" style="top:calc(50% + 2px);left:-7.5%;width:25%;height:62%;border-radius:6px 4px 8px 5px;filter:blur(2px);background:linear-gradient(95deg, rgba(255, 82, 126, 0.125) 0%, rgba(255, 165, 0, 0.1) 100%);transform:translateY(-50%) rotate(1deg) skewX(2deg) scaleX(0);transform-origin:left center;transition:transform 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.05s"></span><span class="absolute z-10" style="top:calc(50% + 2px);right:calc(-7.5% - 15px);width:15%;height:59.8%;border-radius:4px 7px 5px 8px;filter:blur(1.5px);background:linear-gradient(95deg, rgba(255, 165, 0, 0.075) 0%, rgba(255, 165, 0, 0.15) 100%);transform:translateY(-50%) rotate(2deg) skewX(3deg) scaleX(0);transform-origin:left center;transition:transform 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.5s"></span><span class="relative z-10" style="clip-path:inset(0 100% 0 0);transition:clip-path 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94)">PRESSBOX</span></span></div><div class="absolute top-[-30px] sm:top-[-40px] md:top-[-50px] lg:top-[-60px]" style="z-index:0;transform:rotate(-1.5deg);pointer-events:none"><span class="font-knewave text-[60px] sm:text-[90px] md:text-[120px] lg:text-[155px] xl:text-[190px] uppercase inline-block relative" style="transform-origin:center bottom;transform:perspective(500px) rotateX(-8deg);color:transparent"><span class="absolute" style="top:calc(50% + 2px);left:-8%;width:116%;height:67.5%;border-radius:8px 12px 10px 6px;filter:blur(0.5px);background:linear-gradient(95deg, rgba(255, 82, 126, 0.25) 0%, rgba(255, 165, 0, 0.25) 100%);
23transform:translateY(-50%) rotate(-2deg) skewX(-3deg) skewY(2deg) scaleX(0);transform-origin:left center;transition:transform 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94)"></span><span class="absolute" style="top:calc(50% + 2px);left:-7.5%;width:25%;height:62%;border-radius:6px 4px 8px 5px;filter:blur(2px);background:linear-gradient(95deg, rgba(255, 82, 126, 0.2) 0%, rgba(255, 165, 0, 0.15) 100%);transform:translateY(-50%) rotate(1deg) skewX(2deg) scaleX(0);transform-origin:left center;transition:transform 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.05s"></span><span class="absolute" style="top:calc(50% + 2px);right:calc(-7.5% - 15px);width:15%;height:59.8%;border-radius:4px 7px 5px 8px;filter:blur(1.5px);background:linear-gradient(95deg, rgba(255, 165, 0, 0.15) 0%, rgba(255, 165, 0, 0.25) 100%);transform:translateY(-50%) rotate(2deg) skewX(3deg) scaleX(0);transform-origin:left center;transition:transform 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.5s"></span>PRESSBOX</span></div><h1 class="font-proxima-nova-condensed hero-title relative z-10 font-black uppercase italic relative z-10"><span class="relative inline-block"><span class="absolute inset-0" style="-webkit-text-stroke:7px #000;color:#000;filter:drop-shadow(3px 3px 0px rgba(0,0,0,1))" aria-hidden="true"> From the <br/> PressBox </span><span class="relative" style="background-image:linear-gradient(135deg, hsl(179, 72%, 51%) 0%, hsl(256, 73%, 72%) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text"> From the <br/> PressBox </span></span></h1></div><p class="hero-description mx-auto mt-4 w-full text-center font-roc-grotesk text-charcoal sm:mt-5">The future of media & entertainment should be<!-- --> <span class="font-bold"><span class="relative inline-block"><span class="absolute" style="position:absolute;pointer-events:none;z-index:10;mix-blend-mode:multiply;transform-origin:left center;background:linear-gradient(90deg, hsl(345, 100%, 66%) 0%, hsl(25, 100%, 60%) 100%);opacity:0.5;transform:rotate(1deg) skewX(0.5deg) translateY(-50%) scaleX(0);transition:transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);top:50%;left:-0.4em;right:-0.35em;height:65%;border-radius:2px 1px 3px 0px"></span><span class="absolute" style="position:absolute;pointer-events:none;z-index:10;mix-blend-mode:multiply;transform-origin:left center;background:linear-gradient(90deg, hsl(345, 100%, 66%) 0%, hsl(25, 100%, 60%) 100%);opacity:0.45;transform:rotate(0.5deg) skewX(-1deg) translateY(-50%) scaleX(0);transition:transform 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.05s;top:48%;left:-0.38em;width:15%;height:58%;border-radius:1px 0px 2px 1px;filter:blur(1.5px)"></span><span class="absolute" style="position:absolute;pointer-events:none;z-index:10;mix-blend-mode:multiply;transform-origin:left center;background:linear-gradient(90deg, hsl(345, 100%, 66%) 0%, hsl(25, 100%, 60%) 100%);opacity:0.4;transform:rotate(1.5deg) skewX(0.5deg) translateY(-50%) scaleX(0);transition:transform 0.15s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.3s;top:52%;right:-0.32em;width:10%;height:55%;border-radius:0px 2px 1px 2px;filter:blur(1px)"></span>in the hands of fans</span></span>. Read more on how <span class="font-bold italic">PressBox</span> is building the future of<!-- --> <span class="font-bold"><span class="relative inline-block"><span class="absolute" style="position:absolute;pointer-events:none;z-index:10;mix-blend-mode:multiply;transform-origin:left center;background:linear-gradient(90deg, hsl(179, 72%, 51%) 0%, hsl(79, 100%, 70%) 100%);opacity:0.6;transform:rotate(-1deg) skewX(-0.5deg) translateY(-50%) scaleX(0);transition:transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);top:50%;left:-0.4em;right:-0.35em;height:65%;border-radius:2px 1px 3px 0px"></span><span class="absolute" style="position:absolute;pointer-events:none;z-index:10;mix-blend-mode:multiply;transform-origin:left center;background:linear-gradient(90deg, hsl(179, 72%, 51%) 0%, hsl(79, 100%, 70%) 100%);opacity:0.45;transform:rotate(0.5deg) skewX(-1deg) translateY(-50%) scaleX(0);transition:transform 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.05s;top:48%;left:-0.38em;width:15%;height:58%;border-radius:1px 0px 2px 1px;filter:blur(1.5px)"></span><span class="absolute" style="position:absolute;pointer-events:none;z-index:10;mix-blend-mode:multiply;transform-origin:left center;background:linear-gradient(90deg, hsl(179, 72%, 51%) 0%, hsl(79, 100%, 70%) 100%);opacity:0.4;transform:rotate(1.5deg) skewX(0.5deg) translateY(-50%) scaleX(0);transition:transform 0.15s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.3s;top:52%;right:-0.32em;width:10%;height:55%;border-radius:0px 2px 1px 2px;filter:blur(1px)"></span>personalization</span></span>.</p></div></section><div class="[&>div]:!mt-0 [&>div]:!mb-0"><div class="relative z-50 -mt-[130px] mb-[10px] -rotate-1 overflow-visible border-black border-y-[2px] bg-gradient-iron-ore py-[2px] shadow-drop-md sm:mt-[15px] sm:mb-[14px] sm:border-y-[3px] sm:py-[5px] md:mt-[100px] md:mb-[18.225px] xl:mt-[35px]"><div class="overflow-visible border-black border-y-[2px] bg-gradient-silver py-2 sm:border-y-[3px] sm:py-4"><div class="flex h-full w-full items-center justify-center overflow-visible px-4 sm:px-12"><div class="flex items-center justify-center overflow-visible whitespace-nowrap text-center text-[16px] text-white leading-[22px] sm:text-[22.5px] sm:leading-[30px]"><span class="inline-flex items-center font-light text-black capitalize italic opacity-90">Interested?</span><span class="mx-1 inline-flex items-center text-gray-500 opacity-50 sm:mx-2">-</span><div class="group relative inline-flex items-center overflow-visible "><div class="relative inline-block origin-center overflow-visible transition-transform duration-300 ease-out group-hover:-rotate-2 "><a href="https://cal.com/brian-hough-pressbox/demo" target="_blank" rel="noopener noreferrer" class="book-demo-link relative inline-block font-black font-proxima-nova-condensed text-[24px] text-white uppercase italic sm:text-[34px]"><span class="book-demo-text relative inline-block transition-all group-hover:scale-[1.2375]" style="transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);z-index:10;margin-left:-0.15em;margin-right:-0.15em"><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" aria-hidden="true"> BOOK A DEMO! </span><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" style="mix-blend-mode:normal" aria-hidden="true"> BOOK A DEMO! </span><span class="book-demo-text-fill relative drop-shadow-[2px_2px_0px_rgba(0,0,0,0.25)] transition-all duration-300 ease-out"> BOOK A DEMO! </span></span></a></div></div><span class="mx-2 text-gray-500 opacity-50 sm:mx-6">|</span><span class="inline-flex items-center font-light text-black capitalize italic opacity-90">Interested?</span><span class="mx-1 inline-flex items-center text-gray-500 opacity-50 sm:mx-2">-</span><div class="group relative inline-flex items-center overflow-visible odd-index"><div class="relative inline-block origin-center overflow-visible transition-transform duration-300 ease-out group-hover:-rotate-2 "><a href="https://cal.com/brian-hough-pressbox/demo" target="_blank" rel="noopener noreferrer" class="book-demo-link relative inline-block font-black font-proxima-nova-condensed text-[24px] text-white uppercase italic sm:text-[34px]"><span class="book-demo-text relative inline-block transition-all group-hover:scale-[1.2375]" style="transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);z-index:10;margin-left:-0.15em;margin-right:-0.15em"><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" aria-hidden="true"> BOOK A DEMO! </span><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" style="mix-blend-mode:normal" aria-hidden="true"> BOOK A DEMO! </span><span class="book-demo-text-fill relative drop-shadow-[2px_2px_0px_rgba(0,0,0,0.25)] transition-all duration-300 ease-out"> BOOK A DEMO! </span></span></a></div></div><span class="mx-2 text-gray-500 opacity-50 sm:mx-6">|</span><span class="inline-flex items-center font-light text-black capitalize italic opacity-90">Interested?</span><span class="mx-1 inline-flex items-center text-gray-500 opacity-50 sm:mx-2">-</span><div class="group relative inline-flex items-center overflow-visible "><div class="relative inline-block origin-center overflow-visible transition-transform duration-300 ease-out group-hover:-rotate-2 "><a href="https://cal.com/brian-hough-pressbox/demo" target="_blank" rel="noopener noreferrer" class="book-demo-link relative inline-block font-black font-proxima-nova-condensed text-[24px] text-white uppercase italic sm:text-[34px]"><span class="book-demo-text relative inline-block transition-all group-hover:scale-[1.2375]" style="transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);z-index:10;margin-left:-0.15em;margin-right:-0.15em"><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" aria-hidden="true"> BOOK A DEMO! </span><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" style="mix-blend-mode:normal" aria-hidden="true"> BOOK A DEMO! </span><span class="book-demo-text-fill relative drop-shadow-[2px_2px_0px_rgba(0,0,0,0.25)] transition-all duration-300 ease-out"> BOOK A DEMO! </span></span></a></div></div><span class="mx-2 text-gray-500 opacity-50 sm:mx-6">|</span><span class="inline-flex items-center font-light text-black capitalize italic opacity-90">Interested?</span><span class="mx-1 inline-flex items-center text-gray-500 opacity-50 sm:mx-2">-</span><div class="group relative inline-flex items-center overflow-visible odd-index"><div class="relative inline-block origin-center overflow-visible transition-transform duration-300 ease-out group-hover:-rotate-2 "><a href="https://cal.com/brian-hough-pressbox/demo" target="_blank" rel="noopener noreferrer" class="book-demo-link relative inline-block font-black font-proxima-nova-condensed text-[24px] text-white uppercase italic sm:text-[34px]"><span class="book-demo-text relative inline-block transition-all group-hover:scale-[1.2375]" style="transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);z-index:10;margin-left:-0.15em;margin-right:-0.15em"><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" aria-hidden="true"> BOOK A DEMO! </span><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" style="mix-blend-mode:normal" aria-hidden="true"> BOOK A DEMO! </span><span class="book-demo-text-fill relative drop-shadow-[2px_2px_0px_rgba(0,0,0,0.25)] transition-all duration-300 ease-out"> BOOK A DEMO! </span></span></a></div></div><span class="mx-2 text-gray-500 opacity-50 sm:mx-6">|</span><span class="inline-flex items-center font-light text-black capitalize italic opacity-90">Interested?</span><span class="mx-1 inline-flex items-center text-gray-500 opacity-50 sm:mx-2">-</span><div class="group relative inline-flex items-center overflow-visible "><div class="relative inline-block origin-center overflow-visible transition-transform duration-300 ease-out group-hover:-rotate-2 "><a href="https://cal.com/brian-hough-pressbox/demo" target="_blank" rel="noopener noreferrer" class="book-demo-link relative inline-block font-black font-proxima-nova-condensed text-[24px] text-white uppercase italic sm:text-[34px]"><span class="book-demo-text relative inline-block transition-all group-hover:scale-[1.2375]" style="transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);z-index:10;margin-left:-0.15em;margin-right:-0.15em"><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" aria-hidden="true"> BOOK A DEMO! </span><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" style="mix-blend-mode:normal" aria-hidden="true"> BOOK A DEMO! </span><span class="book-demo-text-fill relative drop-shadow-[2px_2px_0px_rgba(0,0,0,0.25)] transition-all duration-300 ease-out"> BOOK A DEMO! </span></span></a></div></div><span class="mx-2 text-gray-500 opacity-50 sm:mx-6">|</span><span class="inline-flex items-center font-light text-black capitalize italic opacity-90">Interested?</span><span class="mx-1 inline-flex items-center text-gray-500 opacity-50 sm:mx-2">-</span><div class="group relative inline-flex items-center overflow-visible odd-index"><div class="relative inline-block origin-center overflow-visible transition-transform duration-300 ease-out group-hover:-rotate-2 "><a href="https://cal.com/brian-hough-pressbox/demo" target="_blank" rel="noopener noreferrer" class="book-demo-link relative inline-block font-black font-proxima-nova-condensed text-[24px] text-white uppercase italic sm:text-[34px]"><span class="book-demo-text relative inline-block transition-all group-hover:scale-[1.2375]" style="transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);z-index:10;margin-left:-0.15em;margin-right:-0.15em"><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" aria-hidden="true"> BOOK A DEMO! </span><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" style="mix-blend-mode:normal" aria-hidden="true"> BOOK A DEMO! </span><span class="book-demo-text-fill relative drop-shadow-[2px_2px_0px_rgba(0,0,0,0.25)] transition-all duration-300 ease-out"> BOOK A DEMO! </span></span></a></div></div><span class="mx-2 text-gray-500 opacity-50 sm:mx-6">|</span><span class="inline-flex items-center font-light text-black capitalize italic opacity-90">Interested?</span><span class="mx-1 inline-flex items-center text-gray-500 opacity-50 sm:mx-2">-</span><div class="group relative inline-flex items-center overflow-visible "><div class="relative inline-block origin-center overflow-visible transition-transform duration-300 ease-out group-hover:-rotate-2 "><a href="https://cal.com/brian-hough-pressbox/demo" target="_blank" rel="noopener noreferrer" class="book-demo-link relative inline-block font-black font-proxima-nova-condensed text-[24px] text-white uppercase italic sm:text-[34px]"><span class="book-demo-text relative inline-block transition-all group-hover:scale-[1.2375]" style="transition:all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);z-index:10;margin-left:-0.15em;margin-right:-0.15em"><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" aria-hidden="true"> BOOK A DEMO! </span><span class="absolute inset-0 text-stroke-gradient transition-all duration-300 ease-out" style="mix-blend-mode:normal" aria-hidden="true"> BOOK A DEMO! </span><span class="book-demo-text-fill relative drop-shadow-[2px_2px_0px_rgba(0,0,0,0.25)] transition-all duration-300 ease-out"> BOOK A DEMO! </span></span></a></div></div></div></div></div></div></div><section class="mx-auto mt-[60px] w-full max-w-[1440px] px-4 pb-16 sm:mt-[72px] sm:px-8 md:mt-[84px] lg:px-12 xl:px-[85px]"><div class="grid grid-cols-1 gap-5 sm:gap-6 md:grid-cols-2 lg:grid-cols-3"><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/building-pressbox-workflows" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://brand-assets.pressbox.studio/019f1fa9-7312-769c-9379-df96b5b0d60d.png" alt="Building PressBox Workflows" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Building PressBox Workflows</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>July 2, 2026</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/feature-friday-may-1s
23t-2026" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://licensed-images.pressbox.studio/pressbox/self-licensed/1775049890710.webp?width=800&format=auto&org=pressbox" alt="Feature Friday - May 1st, 2026" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Feature Friday - May 1st, 2026</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>May 1, 2026</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/pressbox-raises-dollar2m-seed-funding-led-by-relay-ventures" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://brand-assets.pressbox.studio/019dafe6-a82b-788a-9735-628e20429017.png" alt="PressBox Raises $2M Seed Funding Led by Relay Ventures" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">PressBox Raises $2M Seed Funding Led by Relay Ventures</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>April 21, 2026</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/feature-friday-april-17th-2026" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://licensed-images.pressbox.studio/pressbox/self-licensed/1775049890710.webp?org=pressbox" alt="Feature Friday - April 17th, 2026" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Feature Friday - April 17th, 2026</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>April 17, 2026</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/feature-friday-april-10th-2026" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://licensed-images.pressbox.studio/pressbox/self-licensed/1775049890710.webp?width=800&format=auto&org=pressbox" alt="Feature Friday - April 10th, 2026" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Feature Friday - April 10th, 2026</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>April 10, 2026</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/feature-friday-april-3rd-2026" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://licensed-images.pressbox.studio/pressbox/self-licensed/1775049890710.webp?width=800&format=auto&org=pressbox" alt="Feature Friday - April 3rd, 2026" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Feature Friday - April 3rd, 2026</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>April 3, 2026</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/feature-friday-march-27th-2026" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://brand-assets.pressbox.studio/019d2531-7c5f-7991-a491-4f136ea780d1.webp" alt="Feature Friday - March 27th, 2026" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Feature Friday - March 27th, 2026</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>March 27, 2026</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/full-stack-cloudflare-part-3-content-orchestration-at-the-edge" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://brand-assets.pressbox.studio/019d1606-9b5f-7cc9-a193-0d71bfd6252b.webp" alt="Full-stack Cloudflare Part 3 â Content Orchestration at the Edge" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Full-stack Cloudflare Part 3 â Content Orchestration at the Edge</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>October 28, 2025</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/feature-friday-clips" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://brand-assets.pressbox.studio/019d1603-f108-7999-94e1-1ba4bf2e2243.webp" alt="Feature Friday â Clips" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Feature Friday â Clips</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>October 16, 2025</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/building-a-react-based-cli-to-speed-up-development-or-part-2-how" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://brand-assets.pressbox.studio/019d1606-33ea-7999-94e1-35898d83fab4.webp" alt="Building a React-based CLI to Speed Up Development | Part 2: How" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Building a React-based CLI to Speed Up Development | Part 2: How</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>September 23, 2025</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/building-a-react-based-cli-to-speed-up-development-or-part-1-what-why" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://brand-assets.pressbox.studio/019d1605-f5e8-7999-94e1-29aa26e8bba6.webp" alt="Building a React-based CLI to Speed Up Development | Part 1: What + Why" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Building a React-based CLI to Speed Up Development | Part 1: What + Why</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>September 15, 2025</span></div></div></div></a><a class="group flex flex-col overflow-hidden rounded-[10px] border-[4px] border-black bg-gradient-pearl shadow-drop-md transition-all hover:-translate-y-[2px] hover:scale-[1.02]" href="/blog/feature-friday-personalized-audio" data-discover="true"><div class="relative aspect-[16/9] overflow-hidden border-black border-b-[3px]"><img src="https://brand-assets.pressbox.studio/019d1603-c438-7999-94e1-14bd569d61db.webp" alt="Feature Friday â Personalized Audio" class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"/></div><div class="flex flex-1 flex-col px-3 pt-2 pb-2.5 sm:px-4 sm:pt-2.5 sm:pb-3"><h2 class="line-clamp-2 font-black font-proxima-nova-condensed text-[20px] text-black uppercase italic leading-[22px] transition-colors group-hover:text-hitman sm:text-[22px] sm:leading-[24px]">Feature Friday â Personalized Audio</h2><div class="mt-auto flex flex-col gap-1.5 pt-1"><hr class="border-charcoal/10"/><div class="flex items-center gap-2 font-roc-grotesk text-[12px] text-charcoal/50"><span>September 12, 2025</span></div></div></div></a></div><div class="mt-12 flex items-center justify-center gap-3"><span class="font-roc-grotesk text-[15px] text-charcoal/60">Page <!-- -->1<!-- --> of <!-- -->2</span>
23<a class="rounded-inner border-[2px] border-black bg-charcoal px-4 py-2 font-extrabold font-proxima-nova-condensed text-[14px] text-white uppercase shadow-drop-sm transition-transform hover:-translate-y-[1px] hover:scale-105" href="/blog?page=2" data-discover="true">Next</a></div></section><footer id="footer" class="flex justify-center border-black border-t-[2px] bg-gradient-charcoal"><div class="space-t-12 mx-auto flex w-full max-w-[1240px] flex-col px-4 pt-16 sm:px-8 lg:px-[85px]"><div class="flex flex-col items-center justify-center gap-8 sm:gap-12 lg:ml-[65px] lg:flex-row lg:items-start lg:gap-[75px]"><div class="relative mt-[15px] mb-[25px] flex items-center justify-center sm:mb-0" style="transform:rotate(-3deg);z-index:1"><div class="relative " style="perspective:1200px"><div style="transform-style:preserve-3d"><div class="relative flex scale-110 flex-col items-center overflow-visible rounded-lg border-[4px] border-black bg-gradient-pearl text-center font-proxima-nova-condensed shadow-drop-lg" style="transform-origin:center center"><div class="absolute top-0 left-0 z-10 h-full w-full bg-gradient-to-br from-transparent via-white/15 to-white/15"><div class="z-20 h-full w-full bg-[length:30%] bg-[url('/images/backgrounds/pressbox_bg.webp')] opacity-10"></div></div><div class="pointer-events-none absolute top-0 left-0 z-30 flex h-full w-full items-center justify-center overflow-hidden"><div class="absolute h-[200%] w-[200%] mix-blend-screen blur-[40px]" style="background:radial-gradient(circle at center, hsla(179, 72%, 51%, 0.15) 0%, transparent 80%);will-change:auto;transform:translateX(-75%)"></div></div><div class="relative flex w-full flex-col items-center"><div class="relative z-10 w-full pt-[15px]"><div class="w-full border-black border-y-[3px] bg-black py-2"><svg viewBox="0 0 142 26" xmlns="http://www.w3.org/2000/svg" class="mx-auto w-[115px]" role="img" aria-label="PressBox"><path d="M4.356 1.024H11.484C16.308 1.024 18.18 3.508 18.18 7.036C18.18 8.98 17.64 11.716 16.776 13.444C15.588 15.82 13.356 17.116 9.18 17.116H7.272L5.868 25H0.144L4.356 1.024ZM9.288 5.596L8.1 12.544H9.324C10.62 12.544 11.376 12.04 11.772 11.248C12.204 10.42 12.528 8.404 12.528 7.54C12.528 6.28 11.844 5.596 10.404 5.596H9.288ZM24.7815 16.576L23.3055 25H17.5815L21.7935 1.024H28.7775C33.7815 1.024 35.8695 3.076 35.8695 6.784C35.8695 8.728 35.4375 11.284 34.6455 12.868C33.9975 14.2 32.8815 15.136 31.4775 15.748L33.3135 25H27.5175L25.9695 16.576H24.7815ZM26.7255 5.632L25.6095 12.112H26.9055C28.2015 12.112 29.0295 11.572 29.4255 10.78C29.7855 10.06 30.0735 8.836 30.0735 7.648C30.0735 6.244 29.5335 5.632 27.3735 5.632H26.7255ZM40.0044 1.024H53.1084L52.2084 6.244H44.7204L44.0004 10.276H49.6884L48.7884 15.316H43.1004L42.3444 19.78H49.8324L48.8964 25H35.7924L40.0044 1.024ZM62.2637 0.52C67.0517 0.52 69.4277 3.004 69.4277 6.64C69.4277 7.324 69.3197 8.188 69.2117 8.98L63.9917 9.124C64.0997 8.368 64.1717 7.828 64.1717 7.252C64.1717 5.812 63.4157 5.128 62.1557 5.128C60.7877 5.128 59.9957 5.992 59.9957 7.252C59.9957 8.332 60.6437 9.232 63.3797 11.356C66.4037 13.696 67.4477 15.46 67.4477 17.908C67.4477 21.94 65.2157 25.504 59.1677 25.504C54.2357 25.504 51.9677 23.092 51.9677 19.276C51.9677 18.484 52.0757 17.512 52.2917 16.576L57.6197 16.432C57.4397 17.188 57.3677 17.836 57.3677 18.448C57.3677 20.104 58.3037 20.752 59.5997 20.752C61.0397 20.752 61.8317 19.888 61.8317 18.52C61.8317 17.368 61.1117 16.468 58.5917 14.524C55.6037 12.22 54.4517 10.636 54.4517 7.972C54.4517 4.012 56.7917 0.52 62.2637 0.52ZM79.209 0.52C83.997 0.52 86.373 3.004 86.373 6.64C86.373 7.324 86.265 8.188 86.157 8.98L80.937 9.124C81.045 8.368 81.117 7.828 81.117 7.252C81.117 5.812 80.361 5.128 79.101 5.128C77.733 5.128 76.941 5.992 76.941 7.252C76.941 8.332 77.589 9.232 80.325 11.356C83.349 13.696 84.393 15.46 84.393 17.908C84.393 21.94 82.161 25.504 76.113 25.504C71.181 25.504 68.913 23.092 68.913 19.276C68.913 18.484 69.021 17.512 69.237 16.576L74.565 16.432C74.385 17.188 74.313 17.836 74.313 18.448C74.313 20.104 75.249 20.752 76.545 20.752C77.985 20.752 78.777 19.888 78.777 18.52C78.777 17.368 78.057 16.468 75.537 14.524C72.549 12.22 71.397 10.636 71.397 7.972C71.397 4.012 73.737 0.52 79.209 0.52ZM89.9263 1.024H97.6663C101.734 1.024 103.786 3.004 103.786 6.208C103.786 7.54 103.534 9.16 102.994 10.204C102.346 11.5 101.158 12.4 99.2503 12.868V12.94C101.158 13.444 102.238 14.776 102.238 17.08C102.238 18.412 101.914 20.284 101.194 21.724C100.006 24.064 97.5583 25 94.3903 25H85.7143L89.9263 1.024ZM94.6423 5.596L93.7063 10.996H95.4343C96.5863 10.996 97.3423 10.6 97.7743 9.736C98.0623 9.124 98.2423 8.08 98.2423 7.288C98.2423 6.208 97.5943 5.596 96.2623 5.596H94.6423ZM93.0223 14.812L92.0503 20.428H93.9583C95.1823 20.428 95.7583 20.032 96.1543 19.276C96.5143 18.556 96.6943 17.404 96.6943 16.612C96.6943 15.532 96.1183 14.812 94.7143 14.812H93.0223ZM114.912 0.52C118.944 0.52 122.292 2.5 122.292 7.18C122.292 9.7 120.816 18.376 119.448 21.256C118.044 24.208 115.164 25.504 111.96 25.504C107.928 25.504 104.58 23.524 104.58 18.844C104.58 16.324 106.056 7.648 107.424 4.768C108.828 1.816 111.708 0.52 114.912 0.52ZM114.624 5.452C113.688 5.452 112.968 5.848 112.464 6.892C111.636 8.548 110.196 16.684 110.196 18.52C110.196 20.032 111.132 20.572 112.248 20.572C113.184 20.572 113.904 20.176 114.408 19.132C115.236 17.476 116.676 9.34 116.676 7.504C116.676 5.992 115.74 5.452 114.624 5.452ZM132.152 25L130.352 17.404L126.176 25H120.2L127.94 12.256L124.736 1.024H130.604L132.188 8.116L135.968 1.024H141.944L134.564 13.408L138.02 25H132.152Z" fill="white"></path></svg></div></div><div class="relative z-30 flex flex-col items-center pt-[40px] pb-[30px]"><div class="relative mb-[5px] rounded-full border-[5px] border-black bg-gray-300 p-[7px]"><div class="box-border flex h-[135px] w-[135px] items-center justify-center rounded-full border-[6px] border-gray-400 border-dashed bg-gray-300"><div class="opacity-20"><svg xmlns="http://www.w3.org/2000/svg" width="78" height="92" fill="none" viewBox="0 0 78 92" aria-hidden="true"><defs>
23<linearGradient id="alienGradient" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="hsl(0, 0%, 10%)"></stop><stop offset="100%" stop-color="hsl(0, 0%, 3%)"></stop></linearGradient></defs><path fill="url(#alienGradient)" stroke="#000" d="M55.77 80.34l.003-.003c.613-.858 1.213-1.696 1.81-2.414l.006-.007.006-.007c6.424-8.321 11.27-15.739 14.511-22.19C75.344 49.275 77 43.76 77 39.25c0-20.918-17.082-38-38-38s-38 17.082-38 38c0 4.509 1.656 10.026 4.878 16.47 3.225 6.449 8.037 13.864 14.397 22.181l.002.002c.602.844 1.218 1.705 1.837 2.451C26 85.693 30.17 91.416 38.39 91.416h1.098c8.226 0 12.397-5.732 16.284-11.076zM20.938 52.994h0l-.005-.003c-4.37-2.598-7.08-7.319-6.96-12.385h0v-.011c0-.409.25-.867.73-1.158 4.365-2.476 9.791-2.474 14.15.122h0c4.37 2.599 7.081 7.32 6.962 12.385h0v.012c0 .408-.25.865-.73 1.156-2.132 1.183-4.608 1.889-6.953 1.89-2.478-.005-5.074-.716-7.194-2.008zm28.21-13.44c4.36-2.591 9.786-2.593 14.15-.121.48.29.731.749.731 1.157h0v.012c.12 5.062-2.582 9.775-6.938 12.376l-.018.01c-2.249 1.305-4.73 2.008-7.202 2.008-2.364 0-4.838-.591-6.944-1.882l-.004-.002c-.483-.291-.736-.751-.736-1.16 0-5.084 2.6-9.804 6.961-12.397zM39 77.352c-1.78 0-3.215-.328-4.185-.869-.96-.535-1.423-1.246-1.423-2.052s.463-1.517 1.423-2.052c.97-.54 2.405-.87 4.185-.87 1.78 0 3.215.33 4.184.87.96.535 1.424 1.246 1.424 2.052s-.463 1.517-1.423 2.052c-.97.541-2.405.87-4.185.87z"></path></svg></div></div><div class="absolute top-[-6px] left-[-7px] z-40" style="transform-origin:center center;opacity:0;transform:translateZ(300px) scale(0.8) rotate(5deg)"><div class="relative h-[153px] w-[153px] rounded-full border border-black/35 bg-white shadow-md"><div class="box-border h-full w-full rounded-full p-[3px]" style="background:linear-gradient(135deg, #99ffff 0%, #ffff99 15%, #ff99ff 30%, #99ff99 45%, #99dfff 60%, #ffb8d6 75%, #b8ffb8 90%, #ffccff 100%)"><div class="relative box-border h-full w-full rounded-full border border-black/30 bg-gradient-charcoal p-2"><div class="relative box-border flex h-full w-full items-center justify-center overflow-hidden rounded-full border border-black/30 bg-white" style="background-image:linear-gradient(135deg, rgba(153, 255, 255, 0.8) 0%, rgba(255, 255, 153, 0.8) 15%, rgba(255, 153, 255, 0.8) 30%, rgba(153, 255, 153, 0.8) 45%, rgba(153, 223, 255, 0.8) 60%, rgba(255, 184, 214, 0.8) 75%, rgba(184, 255, 184, 0.8) 90%, rgba(255, 204, 255, 0.8) 100%);background-size:cover;background-position:center"><svg xmlns="http://www.w3.org/2000/svg" width="78" height="92" fill="none" viewBox="0 0 78 92" aria-hidden="true"><defs><linearGradient id="alienGradient" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="hsl(0, 0%, 10%)"></stop><stop offset="100%" stop-color="hsl(0, 0%, 3%)"></stop></linearGradient></defs><path fill="url(#alienGradient)" stroke="#000" d="M55.77 80.34l.003-.003c.613-.858 1.213-1.696 1.81-2.414l.006-.007.006-.007c6.424-8.321 11.27-15.739 14.511-22.19C75.344 49.275 77 43.76 77 39.25c0-20.918-17.082-38-38-38s-38 17.082-38 38c0 4.509 1.656 10.026 4.878 16.47 3.225 6.449 8.037 13.864 14.397 22.181l.002.002c.602.844 1.218 1.705 1.837 2.451C26 85.693 30.17 91.416 38.39 91.416h1.098c8.226 0 12.397-5.732 16.284-11.076zM20.938 52.994h0l-.005-.003c-4.37-2.598-7.08-7.319-6.96-12.385h0v-.011c0-.409.25-.867.73-1.158 4.365-2.476 9.791-2.474 14.15.122h0c4.37 2.599 7.081 7.32 6.962 12.385h0v.012c0 .408-.25.865-.73 1.156-2.132 1.183-4.608 1.889-6.953 1.89-2.478-.005-5.074-.716-7.194-2.008zm28.21-13.44c4.36-2.591 9.786-2.593 14.15-.121.48.29.731.749.731 1.157h0v.012c.12 5.062-2.582 9.775-6.938 12.376l-.018.01c-2.249 1.305-4.73 2.008-7.202 2.008-2.364 0-4.838-.591-6.944-1.882l-.004-.002c-.483-.291-.736-.751-.736-1.16 0-5.084 2.6-9.804 6.961-12.397zM39 77.352c-1.78 0-3.215-.328-4.185-.869-.96-.535-1.423-1.246-1.423-2.052s.463-1.517 1.423-2.052c.97-.54 2.405-.87 4.185-.87 1.78 0 3.215.33 4.184.87.96.535 1.424 1.246 1.424 2.052s-.463 1.517-1.423 2.052c-.97.541-2.405.87-4.185.87z"></path></svg></div></div></div></div></div></div><div class="relative w-[300px] overflow-visible pb-[10px]"><div class="absolute bottom-[2px] left-0 z-1 h-1 w-full border-gray-500 border-b-[4px] border-dotted"></div><div class="relative z-2 flex w-full justify-center overflow-visible" style="transform:translateY(12px) rotate(-2deg)"><div class="flex w-full justify-center overflow-hidden"><span class="block whitespace-nowrap px-4 font-knewave text-[32px] text-charcoal uppercase leading-[32px] opacity-90" style="clip-path:polygon(0 0, 0 0, 0 100%, 0 100%);transition:clip-path 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94)">YOUR NAME<br/></span></div></div></div></div></div><div>Â <div class="w-[375px] border-black border-t-[3px] bg-gradient-to-r from-hyper-pumpkin to-hitman pt-[6px] pb-[2px]"><span class="font-black text-[26px] text-black uppercase leading-[24px]">PressBox Insider</span></div><div class="border-black border-y-[3px] bg-black pt-[8px] pb-[5px]"><span class="relative inline-block"><span class="absolute inset-0 bg-gradient-to-r from-electric-lime to-blue-razz bg-clip-text font-black text-[58px] text-transparent uppercase italic leading-[58px]" style="-webkit-text-stroke:6px transparent;paint-order:stroke fill" aria-hidden="true">Â ALL ACCESSÂ </span><span class="relative font-black text-[58px] text-black uppercase italic leading-[58px]">Â ALL ACCESSÂ </span></span></div><div class="flex justify-center py-2"><svg xmlns="http://www.w3.org/2000/svg" width="363" height="33" fill="none" viewBox="0 0 363 33" aria-hidden="true"><path fill="#070707" d="M337.995 32.693V.833h4.86v31.86h-4.86zm6.48 0V.833h4.86v31.86h-4.86zm9.72 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zM312.049 32.693V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86zm9.72 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86zM286.104 32.693V.833h4.86v31.86h-4.86zm6.48 0V.833h4.86v31.86h-4.86zm9.72 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zM260.159 32.693
23V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm6.48 0V.833h4.86v31.86h-4.86zm6.48 0V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86zM234.213 32.693V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm6.48 0V.833h4.86v31.86h-4.86zm6.48 0V.833h4.86v31.86h-4.86zm6.48 0V.833h1.62v31.86h-1.62zM208.268 32.693V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86zm9.72 0V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86zm6.48 0V.833h1.62v31.86h-1.62zM182.323 32.693V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm6.48 0V.833h4.86v31.86h-4.86zm6.48 0V.833h4.86v31.86h-4.86zm6.48 0V.833h1.62v31.86h-1.62zM156.377 32.693V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm6.48 0V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86zm6.48 0V.833h4.86v31.86h-4.86zM130.432 32.693V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86zm9.72 0V.833h4.86v31.86h-4.86zm6.48 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zM104.487 32.693V.833h4.86v31.86h-4.86zm6.48 0V.833h1.62v31.86h-1.62zm6.48 0V.833h4.86v31.86h-4.86zm6.48 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zM78.541 32.693V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm6.48 0V.833h4.86v31.86h-4.86zm6.48 0V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86zM52.596 32.693V.833h4.86v31.86h-4.86zm6.48 0V.833h4.86v31.86h-4.86zm9.72 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zM26.65 32.693V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86zm9.72 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86zM.705 32.693V.833h4.86v31.86H.705zm6.48 0V.833h1.62v31.86h-1.62zm6.48 0V.833h1.62v31.86h-1.62zm3.24 0V.833h1.62v31.86h-1.62zm3.24 0V.833h4.86v31.86h-4.86z"></path></svg></div></div></div><div class="pointer-events-none absolute inset-0 rounded-lg" style="background:none;opacity:0;mix-blend-mode:overlay"></div></div></div></div><div class="relative mb-[10px] flex flex-col space-y-8"><div><div class="w-full max-w-[600px]"><div class="relative mb-3 inline-block"><span class="pointer-events-none absolute" style="transform:rotate(1deg) skewX(-0.5deg) translateY(-50%) scaleX(0);transform-origin:left center;transition:transform 0.24000000000000002s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.2s;top:50%;left:-10px;right:-10px;height:75%;border-radius:2px 1px 3px 0px;z-index:10;background:linear-gradient(90deg, hsl(342, 80%, 66%) 0%, hsl(31, 100%, 60%) 100%);opacity:0.65;mix-blend-mode:multiply"></span><span class="pointer-events-none absolute" style="transform:rotate(0.5deg) skewX(-1deg) translateY(-50%) scaleX(0);transform-origin:left center;transition:transform 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.25s;top:48%;left:-8px;width:8px;height:68%;border-radius:1px 0px 2px 1px;filter:blur(1.5px);z-index:10;background:linear-gradient(90deg, hsl(342, 80%, 66%) 0%, hsl(31, 100%, 60%) 100%);opacity:0.45;mix-blend-mode:multiply"></span><span class="pointer-events-none absolute" style="transform:rotate(1.5deg) skewX(0.5deg) translateY(-50%) scaleX(0);transform-origin:left center;transition:transform 0.28s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.4s;top:52%;right:-8px;width:6px;height:65%;border-radius:0px 2px 1px 2px;filter:blur(1px);z-index:10;background:linear-gradient(90deg, hsl(342, 80%, 66%) 0%, hsl(31, 100%, 60%) 100%);opacity:0.4;mix-blend-mode:multiply"></span><h3 class="section-h3 relative text-[24px] leading-[24px]">Newsletter</h3></div><p class="mb-4 font-roc-grotesk text-lg text-white">Stay up-to-date with the latest in sports tech & media with PressBox.</p><form class="space-y-2"><div class="relative -ml-[3px] rounded-lg bg-black p-[5px] shadow-drop-md"><div class="pointer-events-none absolute inset-0 rounded-lg transition-opacity duration-300" style="background:linear-gradient(90deg, #baff00 0%, #29d8d6 100%);opacity:0"></div><div class="relative flex min-h-[52px] items-center gap-2 overflow-hidden rounded-[3px] px-2 py-1"><input type="email" required="" placeholder="Enter Your Email" class="flex-1 bg-transparent p-[8px] font-roc-grotesk text-[18px] text-charcoal placeholder-gray-500 transition-opacity duration-300 focus:outline-none" style="opacity:0" name="email" value=""/><button class="absolute top-[4px] z-10 flex h-[44px] w-[44px] items-center justify-center overflow-hidden rounded-full border-[3px] border-black bg-gradient-charcoal p-[10px] shadow-drop-sm" type="submit"><div><svg class="absolute" width="0" height="0" aria-hidden="true"><defs><linearGradient id="icon-gradient" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#baff00"></stop><stop offset="100%" stop-color="#29d8d6"></stop></linearGradient></defs></svg><div style="transform:scale(0)"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-send relative z-10 h-[20px] w-[20px]" style="stroke:url(#icon-gradient)"><path d="m22 2-7 20-4-9-9-4Z"></path><path d="M22 2 11 13"></path></svg></div></div></button></div></div><input type="hidden" name="emailConsent" value="true"/><p class="mt-2 font-roc-grotesk text-[13px] text-electric-lime">By submitting your email you consent to receive emails from PressBox.</p></form></div></div><div class="grid grid-cols-2 gap-8 pr-[100px] lg:pr-0"><div class="flex flex-col space-y-8"><div><h3 class="section-h3 mb-4 text-[24px] leading-[24px]" style="color:black;-webkit-text-stroke:6px white">Solutions</h3><div class="flex flex-col space-y-3"><span class="font-roc-grotesk text-[17px] transition-colors duration-200 text-gray-400">Personalization</span><span class="font-roc-grotesk text-[17px] transition-colors duration-200 text-gray-400">Content Studio</span><span class="font-roc-grotesk text-[17px] transition-colors duration-200 text-gray-400">Workflows</span><span class="font-roc-grotesk text-[17px] transition-colors duration-200 text-gray-400">Publishing</span><span class="font-roc-grotesk text-[17px] transition-colors duration-200 text-gray-400">
23Newsroom</span><span class="font-roc-grotesk text-[17px] transition-colors duration-200 text-gray-400">Broadcast</span></div></div></div><div class="flex flex-col space-y-8"><div><h3 class="section-h3 mb-4 text-[24px] leading-[24px]" style="color:black;-webkit-text-stroke:6px white">Company</h3><div class="flex flex-col space-y-3"><a href="/about" class="font-roc-grotesk text-[17px] transition-colors duration-200 text-white hover:text-hitman">About</a><a href="/blog" class="font-roc-grotesk text-[17px] transition-colors duration-200 text-white hover:text-hitman">Blog</a><a href="/support" class="font-roc-grotesk text-[17px] transition-colors duration-200 text-white hover:text-hitman">Support</a></div></div><div><h3 class="section-h3 mb-4 text-[24px] leading-[24px]" style="color:black;-webkit-text-stroke:6px white">Social</h3><div class="flex flex-col space-y-3"><a href="https://www.linkedin.com/company/pressbox" target="_blank" rel="noreferrer" class="font-roc-grotesk text-[17px] transition-colors duration-200 text-white hover:text-hitman">LinkedIn</a></div></div></div></div></div></div><div class="relative z-10 flex flex-col items-center justify-between px-4 pb-8 backdrop-blur-sm md:flex-row" style="background-color:hsla(0, 0%, 10%, 0.7)"><div class="absolute top-0 right-0 left-0 h-px bg-gradient-to-r from-transparent via-gray-400/40 to-transparent"></div><img src="/images/icons/[email protected]" alt="" class="pointer-events-none absolute right-[40px] bottom-[53px] z-10 w-[80px] -scale-x-100 opacity-80 md:w-[100px] xl:right-[5px]"/><div class="my-4 flex w-full flex-col items-center justify-between gap-3 sm:flex-row sm:gap-0 md:mb-0"><div class="relative"><div class="relative z-10 drop-shadow-[3px_3px_0px_rgba(0,0,0,1)]"><svg viewBox="0 0 142 26" xmlns="http://www.w3.org/2000/svg" class="w-[125px]" role="img" aria-label="PressBox"><path d="M4.356 1.024H11.484C16.308 1.024 18.18 3.508 18.18 7.036C18.18 8.98 17.64 11.716 16.776 13.444C15.588 15.82 13.356 17.116 9.18 17.116H7.272L5.868 25H0.144L4.356 1.024ZM9.288 5.596L8.1 12.544H9.324C10.62 12.544 11.376 12.04 11.772 11.248C12.204 10.42 12.528 8.404 12.528 7.54C12.528 6.28 11.844 5.596 10.404 5.596H9.288ZM24.7815 16.576L23.3055 25H17.5815L21.7935 1.024H28.7775C33.7815 1.024 35.8695 3.076 35.8695 6.784C35.8695 8.728 35.4375 11.284 34.6455 12.868C33.9975 14.2 32.8815 15.136 31.4775 15.748L33.3135 25H27.5175L25.9695 16.576H24.7815ZM26.7255 5.632L25.6095 12.112H26.9055C28.2015 12.112 29.0295 11.572 29.4255 10.78C29.7855 10.06 30.0735 8.836 30.0735 7.648C30.0735 6.244 29.5335 5.632 27.3735 5.632H26.7255ZM40.0044 1.024H53.1084L52.2084 6.244H44.7204L44.0004 10.276H49.6884L48.7884 15.316H43.1004L42.3444 19.78H49.8324L48.8964 25H35.7924L40.0044 1.024ZM62.2637 0.52C67.0517 0.52 69.4277 3.004 69.4277 6.64C69.4277 7.324 69.3197 8.188 69.2117 8.98L63.9917 9.124C64.0997 8.368 64.1717 7.828 64.1717 7.252C64.1717 5.812 63.4157 5.128 62.1557 5.128C60.7877 5.128 59.9957 5.992 59.9957 7.252C59.9957 8.332 60.6437 9.232 63.3797 11.356C66.4037 13.696 67.4477 15.46 67.4477 17.908C67.4477 21.94 65.2157 25.504 59.1677 25.504C54.2357 25.504 51.9677 23.092 51.9677 19.276C51.9677 18.484 52.0757 17.512 52.2917 16.576L57.6197 16.432C57.4397 17.188 57.3677 17.836 57.3677 18.448C57.3677 20.104 58.3037 20.752 59.5997 20.752C61.0397 20.752 61.8317 19.888 61.8317 18.52C61.8317 17.368 61.1117 16.468 58.5917 14.524C55.6037 12.22 54.4517 10.636 54.4517 7.972C54.4517 4.012 56.7917 0.52 62.2637 0.52ZM79.209 0.52C83.997 0.52 86.373 3.004 86.373 6.64C86.373 7.324 86.265 8.188 86.157 8.98L80.937 9.124C81.045 8.368 81.117 7.828 81.117 7.252C81.117 5.812 80.361 5.128 79.101 5.128C77.733 5.128 76.941 5.992 76.941 7.252C76.941 8.332 77.589 9.232 80.325 11.356C83.349 13.696 84.393 15.46 84.393 17.908C84.393 21.94 82.161 25.504 76.113 25.504C71.181 25.504 68.913 23.092 68.913 19.276C68.913 18.484 69.021 17.512 69.237 16.576L74.565 16.432C74.385 17.188 74.313 17.836 74.313 18.448C74.313 20.104 75.249 20.752 76.545 20.752C77.985 20.752 78.777 19.888 78.777 18.52C78.777 17.368 78.057 16.468 75.537 14.524C72.549 12.22 71.397 10.636 71.397 7.972C71.397 4.012 73.737 0.52 79.209 0.52ZM89.9263 1.024H97.6663C101.734 1.024 103.786 3.004 103.786 6.208C103.786 7.54 103.534 9.16 102.994 10.204C102.346 11.5 101.158 12.4 99.2503 12.868V12.94C101.158 13.444 102.238 14.776 102.238 17.08C102.238 18.412 101.914 20.284 101.194 21.724C100.006 24.064 97.5583 25 94.3903 25H85.7143L89.9263 1.024ZM94.6423 5.596L93.7063 10.996H95.4343C96.5863 10.996 97.3423 10.6 97.7743 9.736C98.0623 9.124 98.2423 8.08 98.2423 7.288C98.2423 6.208 97.5943 5.596 96.2623 5.596H94.6423ZM93.0223 14.812L92.0503 20.428H93.9583C95.1823 20.428 95.7583 20.032 96.1543 19.276C96.5143 18.556 96.6943 17.404 96.6943 16.612C96.6943 15.532 96.1183 14.812 94.7143 14.812H93.0223ZM114.912 0.52C118.944 0.52 122.292 2.5 122.292 7.18C122.292 9.7 120.816 18.376 119.448 21.256C118.044 24.208 115.164 25.504 111.96 25.504C107.928 25.504 104.58 23.524 104.58 18.844C104.58 16.324 106.056 7.648 107.424 4.768C108.828 1.816 111.708 0.52 114.912 0.52ZM114.624 5.452C113.688 5.452 112.968 5.848 112.464 6.892C111.636 8.548 110.196 16.684 110.196 18.52C110.196 20.032 111.132 20.572 112.248 20.572C113.184 20.572 113.904 20.176 114.408 19.132C115.236 17.476 116.676 9.34 116.676 7.504C116.676 5.992 115.74 5.452 114.624 5.452ZM132.152 25L130.352 17.404L126.176 25H120.2L127.94 12.256L124.736 1.024H130.604L132.188 8.116L135.968 1.024H141.944L134.564 13.408L138.02 25H132.152Z" fill="white"></path></svg></div><div class="pointer-events-none absolute top-1/2 -right-[0.3em] -left-[0.3em] z-20 h-[calc(75%+3px)] -translate-y-1/2 -rotate-1 -skew-x-[0.3deg] rounded-[3px_1px_2px_1px] bg-gradient-to-r from-hitman to-blue-razz opacity-[0.975] mix-blend-multiply"></div></div><div class="flex items-center gap-3"><a href="/terms" class="font-roc-grotesk text-[12px] text-gray-400 transition-colors duration-200 hover:text-gray-200">Terms</a><span class="text-[12px] text-gray-600">·</span><a href="/privacy" class="font-roc-grotesk text-[12px] text-gray-400 transition-colors duration-200 hover:text-gray-200">Privacy</a><span class="text-[12px] text-gray-600">·</span><span class="font-roc-grotesk text-[12px] text-gray-300 italic">©2024 - <!-- -->2026<!-- --> Being Technologies, Inc.</span></div></div></div></div></footer></div></div>
23<script>((storageKey2, restoreKey) => { 24 if (!window.history.state || !window.history.state.key) { 25 let key = Math.random().toString(32).slice(2); 26 window.history.replaceState({ key }, ""); 27 } 28 try { 29 let positions = JSON.parse(sessionStorage.getItem(storageKey2) || "{}"); 30 let storedY = positions[restoreKey || window.history.state.key]; 31 if (typeof storedY === "number") { 32 window.scrollTo(0, storedY); 33 } 34 } catch (error4) { 35 console.error(error4); 36 sessionStorage.removeItem(storageKey2); 37 } 38 })("react-router-scroll-positions", null)</script>
38<script>window.__reactRouterContext = {"basename":"/","future":{"unstable_optimizeDeps":false,"unstable_passThroughRequests":false,"unstable_subResourceIntegrity":false,"unstable_trailingSlashAwareDataRequests":false,"unstable_previewServerPrerendering":false,"v8_middleware":false,"v8_splitRouteModules":false,"v8_viteEnvironmentApi":false},"routeDiscovery":{"mode":"lazy","manifestPath":"/__manifest"},"ssr":true,"isSpaMode":false};window.__reactRouterContext.stream = new ReadableStream({start(controller){window.__reactRouterContext.streamController = controller;}}).pipeThrough(new TextEncoderStream());</script>
38<script type="module" async="">; 39import * as route0 from "/assets/root-mHGU7cF1.js"; 40import * as route1 from "/assets/blog._index-BuUKgbUM.js"; 41 window.__reactRouterManifest = { 42 "entry": { 43 "module": "/assets/entry.client-BwKJ4h79.js", 44 "imports": [ 45 "/assets/rolldown-runtime-CNC7AqOf.js", 46 "/assets/exports-CpC8xO3z.js", 47 "/assets/chunk-62JRHF6Z-b62IZc0S.js", 48 "/assets/react-dom-Bn-YL-V5.js", 49 "/assets/jsx-runtime-DiK4U9sA.js" 50 ], 51 "css": [] 52 }, 53 "routes": { 54 "root": { 55 "id": "root", 56 "path": "", 57 "hasAction": false, 58 "hasLoader": true, 59 "hasClientAction": false, 60 "hasClientLoader": false, 61 "hasClientMiddleware": false, 62 "hasDefaultExport": true, 63 "hasErrorBoundary": true, 64 "module": "/assets/root-mHGU7cF1.js", 65 "imports": [ 66 "/assets/rolldown-runtime-CNC7AqOf.js", 67 "/assets/exports-CpC8xO3z.js", 68 "/assets/chunk-62JRHF6Z-b62IZc0S.js", 69 "/assets/react-dom-Bn-YL-V5.js", 70 "/assets/jsx-runtime-DiK4U9sA.js" 71 ], 72 "css": [ 73 "/assets/root-Bpjm4FGr.css" 74 ] 75 }, 76 "routes/blog._index": { 77 "id": "routes/blog._index", 78 "parentId": "root", 79 "path": "blog", 80 "hasAction": false, 81 "hasLoader": true, 82 "hasClientAction": false, 83 "hasClientLoader": false, 84 "hasClientMiddleware": false, 85 "hasDefaultExport": true, 86 "hasErrorBoundary": false, 87 "module": "/assets/blog._index-BuUKgbUM.js", 88 "imports": [ 89 "/assets/rolldown-runtime-CNC7AqOf.js", 90 "/assets/chunk-62JRHF6Z-b62IZc0S.js", 91 "/assets/jsx-runtime-DiK4U9sA.js", 92 "/assets/Header-BI_BP9KD.js", 93 "/assets/Footer-CkgdE3gs.js", 94 "/assets/SubHeading-CGDbwfzf.js", 95 "/assets/TitleHeading-BX1pHKUv.js", 96 "/assets/CTABanner-DsPF4iVS.js", 97 "/assets/blog-utils-B-ecIOuG.js", 98 "/assets/react-dom-Bn-YL-V5.js" 99 ], 100 "css": [] 101 }, 102 "routes/_index": { 103 "id": "routes/_index", 104 "parentId": "root", 105 "index": true, 106 "hasAction": false, 107 "hasLoader": false, 108 "hasClientAction": false, 109 "hasClientLoader": false, 110 "hasClientMiddleware": false, 111 "hasDefaultExport": true, 112 "hasErrorBoundary": false, 113 "module": "/assets/_index-107llFGb.js", 114 "imports": [ 115 "/assets/rolldown-runtime-CNC7AqOf.js", 116 "/assets/chunk-62JRHF6Z-b62IZc0S.js", 117 "/assets/react-dom-Bn-YL-V5.js", 118 "/assets/jsx-runtime-DiK4U9sA.js", 119 "/assets/Header-BI_BP9KD.js", 120 "/assets/Footer-CkgdE3gs.js", 121 "/assets/SubHeading-CGDbwfzf.js", 122 "/assets/TitleHeading-BX1pHKUv.js", 123 "/assets/Arrow-CehMWh_4.js", 124 "/assets/Heading-BEj4kIj5.js", 125 "/assets/CTABanner-DsPF4iVS.js" 126 ], 127 "css": [] 128 } 129 }, 130 "url": "/assets/manifest-aa08e60c.js", 131 "version": "aa08e60c" 132}; 133 window.__reactRouterRouteModules = {"root":route0,"routes/blog._index":route1}; 134 135import("/assets/entry.client-BwKJ4h79.js");</script>
135<!--$-->
135<script>window.__reactRouterContext.streamController.enqueue("[{\"_1\":2,\"_3\":-5,\"_4\":-5},\"loaderData\",{\"_5\":6,\"_7\":8},\"actionData\",\"errors\",\"root\",{\"_274\":275},\"routes/blog._index\",{\"_9\":10,\"_11\":12},\"posts\",[19,20,21,22,23,24,25,26,27,28,29,30],\"pagination\",{\"_13\":14,\"_15\":16,\"_17\":18},\"page\",1,\"limit\",12,\"total\",16,{\"_31\":258,\"_33\":259,\"_35\":-5,\"_36\":260,\"_38\":261,\"_40\":262,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":263,\"_51\":264,\"_53\":-5,\"_54\":265,\"_56\":266,\"_58\":267,\"_60\":268,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":269,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":270},{\"_31\":244,\"_33\":245,\"_35\":-5,\"_36\":246,\"_38\":247,\"_40\":248,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":249,\"_51\":250,\"_53\":-5,\"_54\":251,\"_56\":252,\"_58\":253,\"_60\":254,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":14,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":255},{\"_31\":227,\"_33\":228,\"_35\":-5,\"_36\":229,\"_38\":230,\"_40\":231,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":232,\"_51\":233,\"_53\":-5,\"_54\":234,\"_56\":235,\"_58\":236,\"_60\":237,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":238,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":239},{\"_31\":210,\"_33\":211,\"_35\":-5,\"_36\":212,\"_38\":213,\"_40\":214,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":215,\"_51\":216,\"_53\":-5,\"_54\":217,\"_56\":218,\"_58\":219,\"_60\":220,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":14,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":221},{\"_31\":196,\"_33\":197,\"_35\":-5,\"_36\":198,\"_38\":199,\"_40\":200,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":201,\"_51\":202,\"_53\":-5,\"_54\":203,\"_56\":204,\"_58\":205,\"_60\":206,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":14,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":207},{\"_31\":181,\"_33\":182,\"_35\":-5,\"_36\":183,\"_38\":184,\"_40\":185,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":186,\"_51\":187,\"_53\":-5,\"_54\":188,\"_56\":189,\"_58\":190,\"_60\":191,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":14,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":192},{\"_31\":164,\"_33\":165,\"_35\":-5,\"_36\":166,\"_38\":167,\"_40\":168,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":169,\"_51\":170,\"_53\":-5,\"_54\":171,\"_56\":172,\"_58\":173,\"_60\":174,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":175,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":176},{\"_31\":144,\"_33\":145,\"_35\":-5,\"_36\":146,\"_38\":147,\"_40\":148,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":149,\"_51\":150,\"_53\":-5,\"_54\":151,\"_56\":152,\"_58\":153,\"_60\":154,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":155,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":156},{\"_31\":129,\"_33\":130,\"_35\":-5,\"_36\":131,\"_38\":132,\"_40\":133,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":134,\"_51\":135,\"_53\":-5,\"_54\":136,\"_56\":137,\"_58\":138,\"_60\":139,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":14,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":140},{\"_31\":114,\"_33\":115,\"_35\":-5,\"_36\":116,\"_38\":117,\"_40\":118,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":119,\"_51\":120,\"_53\":-5,\"_54\":121,\"_56\":122,\"_58\":123,\"_60\":124,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":16,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":125},{\"_31\":95,\"_33\":96,\"_35\":-5,\"_36\":97,\"_38\":98,\"_40\":99,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":100,\"_51\":101,\"_53\":-5,\"_54\":102,\"_56\":103,\"_58\":104,\"_60\":105,\"_62\":-5,\"_63\":64,\"_
13565\":-5,\"_66\":-5,\"_67\":106,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":107},{\"_31\":32,\"_33\":34,\"_35\":-5,\"_36\":37,\"_38\":39,\"_40\":41,\"_42\":-5,\"_43\":44,\"_45\":46,\"_47\":48,\"_49\":50,\"_51\":52,\"_53\":-5,\"_54\":55,\"_56\":57,\"_58\":59,\"_60\":61,\"_62\":-5,\"_63\":64,\"_65\":-5,\"_66\":-5,\"_67\":14,\"_68\":64,\"_69\":-5,\"_70\":-5,\"_71\":-5,\"_72\":64,\"_73\":-5,\"_74\":-5,\"_75\":-5,\"_76\":77},\"id\",\"c9c27698-965a-4d12-bbdb-d84ef65eeb04\",\"title\",\"Feature Friday â Personalized Audio\",\"shortTitle\",\"slug\",\"feature-friday-personalized-audio\",\"webUrl\",\"https://pressbox.pressboxsites.com/posts/feature-friday-personalized-audio\",\"content\",\"\u003cp\u003eOne of PressBoxâs superpowers is the ability to turn our agentsâ vast, up-to-date knowledge of sports into dynamic, personalized, multi-modal content. One of our favorite use cases is \u003cem\u003epersonalized audio\u003c/em\u003e. Audio helps you reach your fans wherever they are, whether itâs on their morning commute, listening at work, or live in the stands.\u003c/p\u003e\u003cp\u003ePressBox offers more than a simple episode creator. In order to truly personalize audio, you need to generate compelling, one-to-one podcasts \u003cem\u003eat scale\u003c/em\u003e. Set a template in our \u003cem\u003eCampaign Builder\u003c/em\u003e, and our team of agents goes to work providing rich, detailed, accurate audio content tailored to every aspect of a fanâs preferences.\u003c/p\u003e\u003cfigure data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d12f5-db42-7006-a1f3-a08428002570.webp\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003ePressBox Podcast Campaigns\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003ePressBox automates the research, quality control, and creation of audio around \u003cem\u003ebreaking news\u003c/em\u003e, \u003cem\u003eevent results\u003c/em\u003e, \u003cem\u003efantasy reports\u003c/em\u003e, \u003cem\u003ebetting intelligence\u003c/em\u003e, \u0026#x26; more! Utilizing best-in-class foundational audio models, your fans can enjoy top-quality, personalized audio in multiple languages:\u003c/p\u003e\u003cfigure class=\\\"embed-figure\\\"\u003e\u003ciframe src=\\\"https://w.soundcloud.com/player/?url=https%3A%2F%2Fsoundcloud.com%2Fpressboxhq%2Fpressbox-monaco-grand-prix-recap%3Futm_source%3Dclipboard%26%23x26%3Butm_medium%3Dtext%26%23x26%3Butm_campaign%3Dsocial_sharing\u0026color=%23ff5500\u0026auto_play=false\u0026hide_related=true\u0026show_comments=false\u0026show_user=true\u0026show_reposts=false\u0026show_teaser=false\u0026visual=true\\\" sandbox=\\\"allow-scripts allow-same-origin allow-popups\\\" allow=\\\"encrypted-media\\\" loading=\\\"lazy\\\" referrerpolicy=\\\"no-referrer\\\" title=\\\"PressBox - Monaco Grand Prix Recap (English)\\\" style=\\\"width:100%;height:166px;border:0;border-radius:0\\\"\u003e\u003c/iframe\u003e\u003cfigcaption\u003ePressBox - Monaco Grand Prix Recap (English)\u003c/figcaption\u003e\u003c/figure\u003e\u003cfigure class=\\\"embed-figure\\\"\u003e\u003ciframe src=\\\"https://w.soundcloud.com/player/?url=https%3A%2F%2Fsoundcloud.com%2Fpressboxhq%2Fpressbox-monaco-grand-prix-recap-spanish%3Futm_source%3Dclipboard%26%23x26%3Butm_medium%3Dtext%26%23x26%3Butm_campaign%3Dsocial_sharing\u0026color=%23ff5500\u0026auto_play=false\u0026hide_related=true\u0026show_comments=false\u0026show_user=true\u0026show_reposts=false\u0026show_teaser=false\u0026visual=true\\\" sandbox=\\\"allow-scripts allow-same-origin allow-popups\\\" allow=\\\"encrypted-media\\\" loading=\\\"lazy\\\" referrerpolicy=\\\"no-referrer\\\" title=\\\"PressBox - Monaco Grand Prix Recap (Spanish)\\\" style=\\\"width:100%;height:166px;border:0;border-radius:0\\\"\u003e\u003c/iframe\u003e\u003cfigcaption\u003ePressBox - Monaco Grand Prix Recap (Spanish)\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003eAudio is just one of the many content formats that PressBox supports to ensure your organization is reaching each and every fan with personalized content. Interested in learning more? \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://pressbox.studio/\\\"\u003e\u003cstrong\u003eVisit Our Site\u003c/strong\u003e\u003c/a\u003e or \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://cal.com/brian-hough-pressbox/demo\\\"\u003e\u003cstrong\u003eBook A Demo\u003c/strong\u003e\u003c/a\u003e!\u003c/p\u003e\",\"excerpt\",\"format\",\"HTML\",\"status\",\"published\",\"language\",\"en\",\"featuredImage\",{\"_88\":89,\"_31\":-5,\"_90\":-5,\"_91\":-5,\"_92\":-5,\"_93\"
135:-5,\"_94\":-5},\"authors\",[78],\"lastEditedBy\",\"tags\",[],\"publishedAt\",\"2025-09-12T00:00:00.000Z\",\"createdAt\",\"2026-03-21T23:25:47.000Z\",\"updatedAt\",\"2026-03-22T16:55:22.000Z\",\"story\",\"isBreakingNews\",false,\"metaTitle\",\"metaDescription\",\"readingTime\",\"ogEnabled\",\"ogTitle\",\"ogDescription\",\"ogImage\",\"xEnabled\",\"xTitle\",\"xDescription\",\"xImage\",\"customHeadlines\",[],{\"_31\":79,\"_80\":81,\"_36\":82,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":87},\"aa32c69a-e91a-4faa-966b-81cccf619b6b\",\"name\",\"Brian Hough\",\"brian-hough\",\"avatarUrl\",\"type\",\"person\",\"socials\",{},\"url\",\"https://brand-assets.pressbox.studio/019d1603-c438-7999-94e1-14bd569d61db.webp\",\"attribution\",\"caption\",\"credit\",\"usageTerms\",\"photographyService\",\"f89dfeba-ccb3-4af3-990b-27d21bea62c5\",\"Building a React-based CLI to Speed Up Development | Part 1: What + Why\",\"building-a-react-based-cli-to-speed-up-development-or-part-1-what-why\",\"https://pressbox.pressboxsites.com/posts/building-a-react-based-cli-to-speed-up-development-or-part-1-what-why\",\"\u003cp\u003eAs a developer, have you ever felt like your terminal tabs were multiplying faster than you could close them, leaving you in a tangled mess of processes and forgotten ports? Weâve been there. Every morning, our development workflow started with a frustrating dance of opening and managing dozens of terminal tabs just to get various services and applications up and running. But what if there was a better way?\u003c/p\u003e\u003ch2\u003eThe Problem\u003c/h2\u003e\u003cp\u003eAt \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://pressbox.studio\\\"\u003ePressBox\u003c/a\u003e, we have a monorepo with React Router/Remix apps, Cloudflare Workers, multiple database servers, and containerized services that all need to run in our local environment. Starting work meant opening/resuming tab after tab in the terminal:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-bash\\\"\u003e# Tab 1\\ncd apps/pressbox \u0026#x26;\u0026#x26; pnpm dev\\n\\n# Tab 2\\ncd apps/grandstand \u0026#x26;\u0026#x26; pnpm dev\\n\\n# Tab 3\\ncd apps/admin \u0026#x26;\u0026#x26; pnpm dev\\n\\n# Tab 4\\ncd workers/curator \u0026#x26;\u0026#x26; pnpm wrangler dev - port 8787\\n\\n# Tab 5\\ncd workers/inbox \u0026#x26;\u0026#x26; pnpm wrangler dev - port 8788\\n\\n# Tab 6â15\\n# ... you get the idea\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eBy lunch, youâve got tabs everywhere. Youâre command-tabbing through windows trying to find the worker thatâs throwing errors, and then you accidentally close the wrong tab. Now you spend 5 minutes figuring out what just died, restarting it, and hoping you got the right port.\u003c/p\u003e\u003cp\u003eWe needed to fix this. Ideally, the solution could live in the command line, where we all spend a lot of time in our development process, but we also werenât in a hurry to write and maintain a collection of Bash scripts.\u003c/p\u003e\u003ch2\u003eThe Solution: PBX CLI\u003c/h2\u003e\u003cp\u003eWhat if we had one customized dashboard instead of dozens of terminal tabs? One place that shows everything at a glance, where you can press a key to start or stop services, can view logs of all services together, easily create and apply database migrations, and a whole lot more.\u003c/p\u003e\u003cp\u003eAfter using Claude Code and other modern CLI tools built using \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://github.com/vadimdemedes/ink\\\"\u003eInk\u003c/a\u003e, we saw how good modern terminal interfaces can be. We considered our local environment and tried out Ink for a few smaller scripts, and thatâs when it really clicked: using React and TypeScript was a pretty powerful way to create CLI tools.\u003c/p\u003e\u003ch2\u003eWhy This Works\u003c/h2\u003e\u003ch3\u003eA Monorepo Sure Helps\u003c/h3\u003e\u003cp\u003ePBX works particularly well because at PressBox, we use a monorepo. Almost everything lives in one place: our React Router apps, Cloudflare Workers, database schemas, and even some containerized services. This means PBX can understand our entire system architecture simply by parsing the file structure - no service registries, no configuration files scattered across repositories, no manual coordination.\u003c/p\u003e\u003cp\u003eThis approach has some caveats, though. Since weâre not running \u003cstrong\u003eeverything\u003c/strong\u003e in containers, it assumes everyone on your team uses similar development environments (weâre all on macOS) and has the same system dependencies installed. If youâre dealing with microservices across multiple repos, or if you have a team split between Mac, Windows, and Linux, youâd probably need to rely more heavily on containerization under the hood â though you could still use a layer of Ink on top.\u003c/p\u003e\u003ch3\u003eReact Knows State Management and UI\u003c/h3\u003e\u003cp\u003eFor us, the monorepo structure combined with Reactâs state management was perfect. Managing services is fundamentally a state management problem: services are either running or stopped, logs stream in real-time, and ports need to be allocated without conflicts. This is something that works pretty well with built-in React state management.\u003c/p\u003e\u003cp\u003eOnce we started with Ink, suddenly we could build real interfaces with proper navigation with arrow keys, color-coded statuses that update in real-time, and live streaming logs. Most of the web development patterns we were already fam
135iliar with \u003cem\u003eactually worked\u003c/em\u003e in the terminal.\u003c/p\u003e\u003ch2\u003eThe Killer Features\u003c/h2\u003e\u003ch3\u003eAutomatic Service Discovery\u003c/h3\u003e\u003cp\u003eAnother nice time saver: PBX automatically discovers new services. Add a new app to the \u003ccode\u003eapps/\u003c/code\u003e directory, a worker to \u003ccode\u003eworkers/\u003c/code\u003e, or a container to \u003ccode\u003econtainers/\u003c/code\u003e, and PBX finds it immediately. When someone adds a new service, everyone else gets it automatically the next time they run PBX. No configuration changes are needed to update a service registry, and no Slack messages are required about new port allocations. It just appears in your dashboard.\u003c/p\u003e\u003ch3\u003eSession Saving/Restoration\u003c/h3\u003e\u003cp\u003eThis turned into one of our favorite features. When you exit PBX, it automatically saves your session (which services were running) in a simple JSON file. Come back later (whether itâs after lunch or the next morning), and if that JSON file exists, PBX asks if you want to restore your previous session:\u003c/p\u003e\u003cp\u003ePress enter or click to view image in full size\u003c/p\u003e\u003cp\u003ePBX Session Restoration\u003c/p\u003e\u003cp\u003eSimply press Enter and youâre back where you left off. No hunting for commands, no remembering which services need to run again. This is huge when youâre context-switching between projects, starting back up after a reboot, or coming back from vacation.\u003c/p\u003e\u003ch3\u003eNo More Port Conflicts\u003c/h3\u003e\u003cp\u003ePort conflicts were getting tough to deal with, too. Someone would hardcode port 3000 for their service or database server, then someone else would use it for another service, and suddenly, nothing works. We fixed this with hash-based deterministic ports:\u003c/p\u003e\u003ch2\u003eGet Andy Crumâs stories in your inbox\u003c/h2\u003e\u003cp\u003eJoin Medium for free to get updates from this writer.\u003c/p\u003e\u003cp\u003eRemember me for faster sign in\u003c/p\u003e\u003cp\u003eNow \u003ccode\u003epressbox\u003c/code\u003ealways gets port 8094 and \u003ccode\u003egrandstand\u003c/code\u003egets 8112. Same port every time, no conflicts, and we donât have to maintain a spreadsheet of whoâs using what. This isnât a perfect solution (the risk of conflicts increases as you add running services), but itâs worked pretty well at our scale.\u003c/p\u003e\u003ch3\u003eDatabase Migrations That Donât Suck\u003c/h3\u003e\u003cp\u003eOne of the best parts of PBX is its handling of database migrations with Drizzle. Instead of memorizing complex migration commands and flags, we built a visual dashboard that makes things clear:\u003c/p\u003e\u003cp\u003ePress enter or click to view image in full size\u003c/p\u003e\u003cp\u003eDB Migration Management in PBX\u003c/p\u003e\u003cp\u003eSome helpful features:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003eCreating a migration? PBX automatically detects when your schema changes and shows you exactly what will change before you commit to it.\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eNeed to update your database? Apply migrations to local or production databases with a single keypress.\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eIs your migrations list getting long and cumbersome? Easily squash multiple migrations together when things get messy.\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eWhen you generate a migration, PBX runs the schema diff, shows you the actual SQL that will execute, asks for a descriptive name, creates the file in the appropriate place, and updates the migration index. No more typing \u003ccode\u003edrizzle-kit generate:sqlite --schema=./src/schema.ts --out=./migrations\u003c/code\u003eand hoping you got the flags right. It just works.\u003c/p\u003e\u003cp\u003eWe also added smart migration warnings right in the status bar, so you always know when there are pending migrations for your databases:\u003c/p\u003e\u003cfigure data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d12f5-1028-7006-a1f3-9f59812c59b2.webp\\\" alt=\\\"\\\"\u003e\u003c/figure\u003e\u003cp\u003ePBX Status Bar, a nice spot to add important data/notifications\u003c/p\u003e\u003ch3\u003eAll Logs in One Place\u003c/h3\u003e\u003cp\u003eAnother key feature of PBX is the ability to see logs from all services in one place. When something breaks across multiple workers and you need to trace a request through your system, you can see everything thatâs happening, with the relevant service name next to each entry. Having logs from every service easily viewable within PBX without having to switch tabs from service to service is a huge advantage.\u003c/p\u003e\u003ch2\u003eThe Impact\u003c/h2\u003e\u003cp\u003e\u003cstrong\u003eLife before PBX:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003eEnvironment setup took 5â7 minutes of hunting for the right commands\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eEveryone had 5â15 terminal tabs open at any given time\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eWe spent way too much time going through tabs looking for the right logs\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003eLife after PBX:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003eMorning setup is typing \u003ccode\u003epbx\u003c/code\u003eand pressing Enter (5 seconds flat)\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eWe need exactly one terminal tab\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eAll logs are in one spot\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eBut the real win isnât just the time savings;
135 itâs that you donât have to think about local infrastructure anymore. Your brain is free to focus on actually building things instead of managing terminal tabs.\u003c/p\u003e\u003ch3\u003eWhat We Learned\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003eReact works great for CLIs.\u003c/strong\u003e After working with it for a few minutes, we knew Ink was the right choice. Our team already knows TypeScript and React, so now we can build CLI features very easily and quickly.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eDirect process management beats containers for local dev (with caveats).\u003c/strong\u003e This works great for us because weâre all on macOS with the same Node versions and system dependencies. Managing processes directly is faster, uses less memory, and has zero Docker Desktop overhead. Again, if youâre running different language runtimes or your team uses different operating systems, containers are still going to be really helpful, but a wrapper like PBX on top of those containers could still be worth considering.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eMonorepos create a lot of possibilities.\u003c/strong\u003e Having everything in one place means PBX can understand your entire system just by reading the filesystem â no API calls to service registries, no syncing configuration between repos. When everything lives together, your tooling can be smarter.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eSmall things matter.\u003c/strong\u003e Session restore, good defaults, and consistent keyboard shortcuts â they all add up to a much better experience. Since developers are the users, itâs easy to solve âpaper cutsâ and general time-wasting activities when you have a framework like this for dev tooling.\u003c/p\u003e\u003ch2\u003eThe Bottom Line\u003c/h2\u003e\u003cp\u003eBuilding something custom with React for CLIs might sound weird at first, but for us, it made a lot of sense. We went from terminal tab bloat to one clean interface that is extensible and just works. Developer setup went from hunting for commands and remembering ports to simply typing three characters.\u003c/p\u003e\u003cp\u003eThe \u003cem\u003ebest\u003c/em\u003e developer tools are those that are built off-the-shelf and solve your exact problem with little to no effort. The \u003cem\u003esecond-best\u003c/em\u003e developer tools are the ones that you build yourself using the technologies you already know to directly solve the problems you have. When your whole team knows the tech stack, everyone can contribute to making the tool better and improving the whole experience; thatâs how a tool becomes a living project that evolves with your needs.\u003c/p\u003e\u003ch2\u003eNext Timeâ¦\u003c/h2\u003e\u003cp\u003eIn Part 2, weâll dive deeper into the technical implementation â how we built the process management system, implemented service discovery, how the UI works, and more. Stay tuned!\u003c/p\u003e\u003cp\u003e\u003cem\u003eUpdate: you can find \u003c/em\u003e\u003ca target=\\\"_blank\\\" rel=\\\"noopener noreferrer nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer\\\" href=\\\"https://pressbox.studio/blog/building-a-react-based-cli-to-speed-up-development-or-part-2-how\\\"\u003e\u003cem\u003epart 2 here\u003c/em\u003e\u003c/a\u003e\u003cem\u003e.\u003c/em\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\",{\"_88\":113,\"_31\":-5,\"_90\":-5,\"_91\":-5,\"_92\":-5,\"_93\":-5,\"_94\":-5},[108],[],\"2025-09-15T00:00:00.000Z\",\"2026-03-22T00:00:03.000Z\",\"2026-03-23T01:49:29.000Z\",9,[],{\"_31\":109,\"_80\":110,\"_36\":111,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":112},\"93fcf06a-d392-46f6-8f90-a360d262e01d\",\"Andy Crum\",\"andy-crum\",{},\"https://brand-assets.pressbox.studio/019d1605-f5e8-7999-94e1-29aa26e8bba6.webp\",\"cd1c1c7e-3876-4566-a76f-1542ce85b68f\",\"Building a React-based CLI to Speed Up Development | Part 2: How\",\"building-a-react-based-cli-to-speed-up-development-or-part-2-how\",\"https://pressbox.pressboxsites.com/posts/building-a-react-based-cli-to-speed-up-development-or-part-2-how\",\"\u003cp\u003eIn \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer z qf\\\" href=\\\"https://pressbox.studio/blog/building-a-react-based-cli-to-speed-up-development-or-part-1-what-why\\\"\u003ePart 1\u003c/a\u003e, we explored the problem that PBX solves for our team at \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer z qf\\\" href=\\\"https://pressbox.studio\\\"\u003ePressBox\u003c/a\u003e: locally managing 10+ services, databases, and workers without getting overwhelmed by terminal tabs. We talked about how features like session persistence, automatic discovery, and deterministic ports transformed our development workflow by centralizing common workflows and saving us loads of time.\u003c/p\u003e\u003ch2\u003eThe Architecture: Three Pillars\u003c/h2\u003e\u003cp\u003ePBX
135is essentially a system orchestrator that happens to run on your laptop. The entire system rests on three core pillars that work together:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eProcess Orchestration: \u003c/strong\u003eStart, stop, track, and recover services reliably\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eSmart Discovery: \u003c/strong\u003eFind services automatically with flexible configuration overrides\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eTerminal UI: \u003c/strong\u003eReal-time status updates for everything, built with React\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003eEach piece solves a specific problem that every growing development team faces. Letâs dig into how we built each one.\u003c/p\u003e\u003ch2\u003eProcess Orchestration: The Foundation\u003c/h2\u003e\u003ch3\u003eThe Lifecycle Challenge\u003c/h3\u003e\u003cp\u003eTracking processes sounds simple on the surface. Nodeâs \u003ccode\u003echild_process.spawn()\u003c/code\u003e gives you a PID. Great! But what happens when PBX crashes, or when someone force-quits the terminal? Youâve got zombie processes everywhere.\u003c/p\u003e\u003cp\u003eOur first attempt was naive: just spawn processes and hope for the best. That lasted about a day before we had dozens of orphaned services running on random ports, eating up CPU and memory. We needed something slightly more robust:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003eclass ServerManager {\\n private services: Map\u0026#x3C;string, Service\u003e = new Map();\\n\\n async startService(id: string) {\\n const service = this.services.get(id);\\n if (!service) return;\\n\\n // each service knows its own startup command\\n const child = spawn(service.command, service.args, {\\n cwd: service.directory,\\n detached: true,\\n });\\n\\n // capture logs in a ring buffer (circular array that overwrites old data)\\n child.stdout.on(\\\"data\\\", (data) =\u003e {\\n service.logs.push(data.toString());\\n\\n // keep last 1000 lines per service\\n if (service.logs.length \u003e 1000) {\\n service.logs.shift();\\n }\\n });\\n\\n // track the PID so we can manage it later\\n await processService.addProcess(id, child.pid, port);\\n }\\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThat \u003ccode\u003eprocessService.addProcess()\u003c/code\u003e call is crucial. We write every PID to a JSON file:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-json\\\"\u003e// /tmp/.pbx/cache/pids.json\\n{\\n \\\"pressbox\\\": { \\\"pid\\\": 12345, \\\"port\\\": 8176, \\\"startedAt\\\": \\\"2025-09-01T...\\\" },\\n \\\"editorial-db\\\": { \\\"pid\\\": 12346, \\\"port\\\": 8094, \\\"startedAt\\\": \\\"2025-09-01T...\\\" }\\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWhen PBX starts, it checks this file. Are those processes still running? If they are, it can adopt them. If PBX crashed last time, you get the option to clean up leftover processes or keep them running. Storing the process information in this simple persistence layer solved 95% of our zombie process problems.\u003c/p\u003e\u003ch3\u003eThe Shutdown Dance\u003c/h3\u003e\u003cp\u003eProcess cleanup on macOS turned out to be trickier than expected. SIGTERM doesnât always work, especially with processes that spawn their own children. We implemented an escalating shutdown sequence:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-typescript\\\"\u003easync stopService(serviceId: string): Promise\u0026#x3C;void\u003e {\\n return new Promise((resolve, reject) =\u003e {\\n const timeout = setTimeout(() =\u003e {\\n // nuclear option after 10 seconds\\n processInfo.process.kill(\\\"SIGKILL\\\");\\n reject(new Error(`Service ${serviceId} failed to stop gracefully`));\\n }, 10000);\\n\\n processInfo.process.once(\\\"exit\\\", () =\u003e {\\n clearTimeout(timeout);\\n resolve();\\n });\\n\\n // try graceful shutdown first\\n processInfo.process.kill(\\\"SIGTERM\\\");\\n });\\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eFirst, we try SIGTERM (\u003cem\u003eplease stop\u003c/em\u003e), wait 10 seconds, then SIGKILL (\u003cem\u003estop NOW\u003c/em\u003e). Itâs not elegant, but it works. Zombie processes are real, and theyâre annoying.\u003c/p\u003e\u003ch2\u003eSession Persistence: Your Safety Net\u003c/h2\u003e\u003cp\u003eOne of the most valuable features is session persistence. Nothing is worse than accidentally hitting Ctrl-C and losing your entire development environment. Hereâs how we prevent that disaster:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003eexport const App = () =\u003e {\\n const [screen, setScreen] = useState('main');\\n const [services, setServices] = useState([]);\\n const { exit } = useApp();\\n\\n // check for restorable session on mount\\n useEffect(() =\u003e {\\n checkForSession().then(session =\u003e {\\n if (session) {\\n setScreen('restore-prompt');\\n }\\n });\\n }, []);\\n\\n // set up graceful shutdown\\n useEffect(() =\u003e {\\n process.on('SIGINT', async () =\u003e {\\n await saveSession();\\n await stopAllServices();
135\\n exit();\\n });\\n }, []);\\n\\n return (\\n \u0026#x3C;Box flexDirection=\\\"column\\\"\u003e\\n \u0026#x3C;Header /\u003e\\n \u0026#x3C;StatusBar services={services} /\u003e\\n\\n {screen === 'main' \u0026#x26;\u0026#x26; \u0026#x3C;MainMenu onSelect={setScreen} /\u003e}\\n {screen === 'services' \u0026#x26;\u0026#x26; \u0026#x3C;ServerDashboard /\u003e}\\n {screen === 'databases' \u0026#x26;\u0026#x26; \u0026#x3C;DatabaseDashboard /\u003e}\\n {screen === 'restore-prompt' \u0026#x26;\u0026#x26; \u0026#x3C;RestorePrompt /\u003e}\\n\\n \u0026#x3C;Footer /\u003e\\n \u0026#x3C;/Box\u003e\\n );\\n};\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWhen someone hits Ctrl-C, we intercept it, save the current state, and then exit cleanly. On startup, we check for that saved state and offer to restore it. As it turns out, this saves us a lot of time.\u003c/p\u003e\u003ch2\u003eSmart Discovery with Flexible Configuration\u003c/h2\u003e\u003ch3\u003eAutomatic Service Discovery\u003c/h3\u003e\u003cp\u003eWe wanted PBX to work immediately after cloning a repo, no configuration required. It walks y
135our filesystem looking for services, understanding the nuances of our monorepo structure:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003efunction discoverServices() {\\n const services = [];\\n\\n // find all React Router apps\\n for (const dir of fs.readdirSync(\\\"apps\\\")) {\\n const packageJson = readPackageJson(`apps/${dir}`);\\n if (packageJson) {\\n services.push({\\n type: \\\"app\\\",\\n name: dir,\\n path: `apps/${dir}`,\\n // smart command detection based on available scripts\\n command: packageJson.scripts.dev ? \\\"pnpm dev\\\" : \\\"pnpm start\\\",\\n // extract port from vite.config if present\\n port: extractPortFromConfig(`apps/${dir}/vite.config.ts`),\\n });\\n }\\n }\\n\\n // find all Cloudflare Workers\\n for (const dir of fs.readdirSync(\\\"workers\\\")) {\\n if (hasWranglerConfig(`workers/${dir}`)) {\\n services.push({\\n type: \\\"worker\\\",\\n name: dir,\\n path: `workers/${dir}`,\\n command: \\\"pnpm wrangler dev\\\",\\n });\\n }\\n }\\n\\n // Containers use npm, not pnpm (they're outside the workspace)\\n for (const dir of fs.readdirSync(\\\"containers\\\")) {\\n const packageJson = readPackageJson(`containers/${dir}`);\\n if (packageJson?.scripts?.build \u0026#x26;\u0026#x26; packageJson?.scripts?.start) {\\n services.push({\\n type: \\\"container\\\",\\n name: dir,\\n path: `containers/${dir}`,\\n command: \\\"npm run build \u0026#x26;\u0026#x26; npm start\\\",\\n });\\n }\\n }\\n\\n return services;\\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe discovery system understands subtle differences that are tailored to how we generally have things set up: containers use \u003ccode\u003enpm\u003c/code\u003e because theyâre outside the pnpm workspace, Cloudflare Workers need \u003ccode\u003ewrangler\u003c/code\u003e, and apps typically use Vite and React Router. It uses these standards to automatically set up new apps, workers, or containers.\u003c/p\u003e\u003cp\u003eBut sometimes you need to override defaults or add environment variables. Thatâs where the PBX \u003ccode\u003econfig.json\u003c/code\u003e file provides escape hatches:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-json\\\"\u003e// pbx/config.json\\n{\\n \\\"localServers\\\": {\\n \\\"services\\\": {\\n \\\"worker-curator\\\": {\\n \\\"command\\\": \\\"pnpm wrangler dev --port 8787\\\",\\n \\\"port\\\": 8787,\\n \\\"env\\\": { \\\"DEBUG\\\": \\\"true\\\" }\\n }\\n }\\n }\\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003ePBX merges these overrides with discovered services, so you get the best of both worlds: zero-config startup that just works, along with flexibility when you need it.\u003c/p\u003e\u003ch3\u003eDeterministic Port Assignment: No More Conflicts\u003c/h3\u003e\u003cp\u003ePort conflicts started to get us pretty quickly. You start your database, and it grabs port 8080. Start another service, portâs taken. Now youâre hunting for free ports, updating config files, and generally wasting time.\u003c/p\u003e\u003cp\u003eWe solved this permanently with deterministic port assignment using MurmurHash3, a non-cryptographic hash algorithm designed for hash table distribution. It takes our service name and transforms it into a uniformly distributed number through a series of multiplication and bit-shifting operations. The beauty of this is its excellent avalanche effect: change one character in the service name, and you get a completely different port. This ensures our 300-port range (8080â8379) gets utilized evenly across all services.\u003c/p\u003e\u003cp\u003eNow \u003ccode\u003eeditorial-db\u003c/code\u003e always gets port 8094. \u003ccode\u003epressbox\u003c/code\u003e always gets 8176. No state files, no coordination, just math. The same service gets the same port every time, across every developerâs machine. Itâs one of those simple solutions that eliminates an entire class of problems. Itâs worth noting that this does not scale forever (the probability of conflicts increases as you add running services and databases), but itâs good enough for now.\u003c/p\u003e\u003ch2\u003eWrapping External Tools: The Reality of Development\u003c/h2\u003e\u003cp\u003ePBX doesnât try to replace existing tools completely â our focus was on making them easier to use. We wrap CLIs like \u003ccode\u003eturso\u003c/code\u003e and \u003ccode\u003ewrangler\u003c/code\u003e to provide better ergonomics for local development.\u003c/p\u003e\u003ch3\u003eTaming Turso Database Management\u003c/h3\u003e\u003cp\u003eStarting a local Turso database manually requires remembering specific flags and paths:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-bash\\\"\u003eturso dev --port 8094 --db-file _local_db/turso/editorial-db.db\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWith PBX, thatâs automated. But more importantly, PBX handles the edge cases we discovered the hard
135way:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003easync stopDatabase(dbName: string) {\\n const port = getPort(dbName);\\n const pid = await isPortListening(port);\\n\\n if (pid) {\\n await killProcess(pid);\\n // turso sometimes leaves orphans, so double-check\\n await sleep(1000);\\n if (await isPortListening(port)) {\\n // nuclear option: pkill\\n await execAsync(`pkill -f \\\"turso dev --port ${port}\\\"`);\\n }\\n }\\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eSome CLI tools donât always clean up after themselves, but now PBX handles it gracefully.\u003c/p\u003e\u003ch3\u003eSimplifying Cloudflare Worker Secrets\u003c/h3\u003e\u003cp\u003eCloudflare Workers need secrets. The only way to add them is through the \u003ccode\u003ewrangler\u003c/code\u003e CLI tool or on the Cloudflare dashboard, which can be tough depending on what directory youâre in and/or how many different workers need the secret. Setting them manually for 20+ workers is error-prone:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-bash\\\"\u003eecho \\\"secret-value\\\" | pnpm wrangler secret put SECRET_NAME --env staging\u003c/code\u003e\u003c/pre\u003e\u003cp\u003ePBX wraps this in a better interface, letting you deploy secrets to one or many workers at once:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003easync addSecretToMultipleServices(serviceIds, secretName, secretValue) {\\n for (const serviceId of serviceIds) {\\n const command = `echo \\\"${secretValue}\\\" | pnpm wrangler secret put ${secretName}`;\\n await execAsync(command, { cwd: service.path });\\n }\\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eSelect workers from a checkbox list, enter the secret once, and deploy everywhere; no more copy-pasting commands and hoping you didnât miss one.\u003c/p\u003e\u003ch2\u003eTerminal UI: React Where You Least Expect It\u003c/h2\u003e\u003ch3\u003eWhy React Actually Makes Sense Here\u003c/h3\u003e\u003cp\u003eReact components rendering in a terminal sounds weird, but managing services is fundamentally a state management problem: services are running or stopped, logs are streaming, and ports need tracking. Creating user interfaces and tracking state is exactly what React was designed to handle.\u003c/p\u003e\u003cp\u003eTraditional bash scripts give you static output:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-bash\\\"\u003e# Traditional approach - fire and forget\\necho \\\"Starting databaseâ¦\\\"\\nturso dev --port 8080 \u0026#x26;\\necho \\\"Database started on port 8080\\\"\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWe needed real-time status updates for 10+ services, interactive navigation, and a UI that any developer could extend. \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer z qf\\\" href=\\\"https://github.com/vadimdemedes/ink\\\"\u003eInk\u003c/a\u003e gave us actual components:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003e// Ink - real components with state\\nconst DatabaseStatus = ({ database }) =\u003e (\\n \u0026#x3C;Box\u003e\\n \u0026#x3C;Text color={database.running ? \\\"green\\\" : \\\"gray\\\"}\u003e\\n {database.running ? \\\"â\\\" : \\\"â\\\"} {database.name}\\n \u0026#x3C;/Text\u003e\\n {database.starting \u0026#x26;\u0026#x26; \u0026#x3C;Spinner type=\\\"dots\\\" /\u003e}\\n \u0026#x3C;/Box\u003e\\n);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eNow we have interfaces with arrow key navigation, color-coded statuses that update in real-time, and components our whole team already knows how to write. The terminal became just another render target.\u003c/p\u003e\u003ch3\u003ePerformance: Not Melting Your Terminal\u003c/h3\u003e\u003cp\u003eHereâs something we learned the hard way: when youâre rendering 20+ status indicators that all update independently, Reactâs re-rendering can destroy your terminal performance. Every log line from every service triggered a full re-render. The terminal would lag, flicker, and eventually crash.\u003c/p\u003e\u003cp\u003eThe solution was careful state management and ring buffers (circular arrays that over
135write old data) for everything:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003e// capture logs in a ring buffer - not unlimited arrays\\nchild.stdout.on(\\\"data\\\", (data) =\u003e {\\n service.logs.push(data.toString());\\n\\n // only keep last 1000 lines per service\\n if (service.logs.length \u003e 1000) {\\n service.logs.shift();\\n }\\n});\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eFor the aggregated log view that shows all services at once, we had to be even more careful:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003econst AggregatedLogs = ({ services }) =\u003e {\\n const [logs, setLogs] = useState([]);\\n\\n useEffect(() =\u003e {\\n // subscribe to all service logs\\n const unsubscribes = services.map((service) =\u003e\\n service.onLog((entry) =\u003e {\\n setLogs(\\n (prev) =\u003e\\n [\\n ...prev,\\n {\\n ...entry,\\n service: service.name,\\n },\\n ].slice(-10000), // keep last 10000 lines total\\n );\\n }),\\n );\\n\\n return () =\u003e unsubscribes.forEach((fn) =\u003e fn());\\n }, [services]);\\n\\n return \u0026#x3C;LogViewer logs={logs} showServiceName /\u003e;\\n};\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThat \u003ccode\u003e.slice(-10000)\u003c/code\u003e prevents infinite memory growth. Without it, the UI would gradually slow down until it became unusable, but with it, PBX can run for days without issues.\u003c/p\u003e\u003ch3\u003eBuilding an Actual Terminal UI\u003c/h3\u003e\u003cp\u003eThe dashboard needs to show everything at once while staying responsive. Hereâs the core interaction model:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003econst ServerDashboard = () =\u003e {\\n const [services, setServices] = useState([]);\\n const [selected, setSelected] = useState(0);\\n\\n useInput((input, key) =\u003e {\\n if (key.upArrow) setSelected(s =\u003e Math.max(0, s - 1));\\n if (key.downArrow) setSelected(s =\u003e Math.min(services.length - 1, s + 1));\\n if (input === ' ') toggleService(services[selected]); // space bar toggles\\n if (input === 'l') showLogs(services[selected]);\\n if (input === 'r') restartService(services[selected]);\\n });\\n\\n return (\\n \u0026#x3C;Box flexDirection=\\\"column\\\"\u003e\\n \u0026#x3C;Box marginBottom={1}\u003e\\n \u0026#x3C;Text bold\u003eLocal Services ({running}/{total} running)\u0026#x3C;/Text\u003e\\n \u0026#x3C;/Box\u003e\\n\\n {services.map((service, i) =\u003e (\\n \u0026#x3C;Box key={service.id}\u003e\\n \u0026#x3C;Text color={i === selected ? 'blue' : 'white'}\u003e\\n {i === selected ? '\u003e' : ' '}\\n \u0026#x3C;/Text\u003e\\n \u0026#x3C;ServiceRow service={service} /\u003e\\n \u0026#x3C;/Box\u003e\\n ))}\\n\\n \u0026#x3C;Box marginTop={1}\u003e\\n \u0026#x3C;Text dimColor\u003e\\n ââ Navigate ⢠Space: Start/Stop ⢠L: Logs ⢠R: Restart\\n \u0026#x3C;/Text\u003e\\n \u0026#x3C;/Box\u003e\\n \u0026#x3C;/Box\u003e\\n );\\n};\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eArrow keys navigate, space bar toggles services, and single letters trigger actions. The \u003ccode\u003euseInput\u003c/code\u003e hook from Ink handles all keyboard input. It feels like a native terminal application, but itâs just React components.\u003c/p\u003e\u003ch2\u003eSome Lessons Learned\u003c/h2\u003e\u003cp\u003eBuilding PBX taught us several hard lessons:\u003c/p\u003e\u003cp\u003e\u003cstrong\u003ePID tracking from day one.\u003c/strong\u003e We didnât do this initially and spent hours hunting zombie processes during development. Always persist PIDs to disk immediately; youâll need them when things go wrong.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eProcess cleanup is harder than starting processes.\u003c/strong\u003e Getting services running is easy, but making sure they properly stop, especially on unexpected exit, requires careful signal handling and fallback strategies.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eMemory management matters in terminals.\u003c/strong\u003e Terminal UIs donât have infinite memory. Use ring buffers, limit array sizes, or watch your CLI slowly grind to a halt as logs accumulate.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eReact.memo is critical for terminal performance.\u003c/strong\u003e When you have 50+ components updating independently, careful memoization is the difference between smooth updates and a flickering mess.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eThe terminal is just another render target.\u003c/strong\u003e Once you accept that, React patterns make perfect sense. Components, hooks, state management⦠it all translates directly.\u003c/p\u003e\u003ch2\u003eThe Bigger Picture: When to Build Your Own\u003c/h2\u003e\u003cp\u003ePBX works for us because we have specific constraints: a consistent monorepo structure, a team that knows React and TypeScript, and somewhat complex local development needs⦠but the patterns weâve discovered are universal.\u003c/p\u003e\u003cp\u003eIf youâre drowning in terminal tabs, fighting port conflicts, or losing work to accidental Ctrl-C, these solutions will help. You donât need to build a full PBX; even implementing just PID tracking or deterministic ports will improve your workflow.\u003c/p\u003e\u003cp\u003eThe beauty of building on React is that extending PBX is just writing more components. Weâll continue to add features as needed. Things that weâre looking at adding next include a headless mode for CI environments (and for calling from other scripts/integration with coding AI assistants), service dependency graphs, and better resource tracking. Each new feature is just another component in the tree.\u003c/p\u003e\u003cp\u003eThe terminal doesnât have to be a constraint. With the right abstractions, it becomes a powerful platform for building the exact tools your team needs. If youâre interested in building tooling like PBX for yourself, try it out! You may save yourself and your team a lot of time.\u003c/p\u003e\",{\"_88\":128,\"_31\":-5,\"_90\":-5,\"_91\":-5,\"_92\":-5,\"_93\"
135:-5,\"_94\":-5},[126],[],\"2025-09-23T01:03:00.000Z\",\"2026-03-22T01:03:15.000Z\",\"2026-03-23T01:48:31.000Z\",[],{\"_31\":109,\"_80\":110,\"_36\":111,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":127},{},\"https://brand-assets.pressbox.studio/019d1606-33ea-7999-94e1-35898d83fab4.webp\",\"25defd7c-47e0-482e-b7ac-abb2b97ab5c5\",\"Feature Friday â Clips\",\"feature-friday-clips\",\"https://pressbox.pressboxsites.com/posts/feature-friday-clips\",\"\u003cp\u003eThis month, we rolled out one of our most requested features: \u003cstrong\u003e\u003cem\u003eClips!\u003c/em\u003e \u003c/strong\u003eWith \u003cem\u003eClips\u003c/em\u003e, PressBox customers can easily turn long-form audio and video into \u003cem\u003epersonalized, short-form conten\u003c/em\u003et that speaks to every fanâs interests. Our agents automatically ingest your long-form content, creating a \u003cem\u003esearchable library\u003c/em\u003e\u003cstrong\u003e\u003cem\u003e \u003c/em\u003e\u003c/strong\u003eof\u003cem\u003e \u003c/em\u003eshort-form Clips that can be utilized across PressBoxâs suite of content tools.\u003c/p\u003e\u003cp\u003eOur agents then utilize this growing library of content to power workflows across the organization, providing our customers with everything from editorial and \u003cem\u003ebroadcast research\u003c/em\u003e, \u003cem\u003elive highlight identification\u003c/em\u003e, \u003cem\u003epersonalized video packages\u003c/em\u003e, \u003cem\u003ecustom social videos\u003c/em\u003e, and more.\u003c/p\u003e\u003cfigure data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d130b-8007-7447-a526-cbfe3b1c2779.webp\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003ePressBox Video Clips\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cem\u003eClips\u003c/em\u003e also supercharges PressBoxâs media monitoring capabilities, providing our customers with detailed breakdowns of video and podcast coverage, ensuring you donât miss key\u003cem\u003e moments\u003c/em\u003e, \u003cem\u003equotes\u003c/em\u003e, and \u003cem\u003ediscussion\u003c/em\u003e from first and third-party coverage.\u003c/p\u003e\u003cfigure data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d130a-16d7-7447-a526-c61752146304.webp\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003ePressBox Media Monitoring\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cem\u003eClips\u003c/em\u003e is one of the many ways PressBox helps our customers get the most out of existing content and coverage, simplifying personalization, and expanding the ways you reach fans of all interests. Excited to learn more? \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://pressbox.studio/\\\"\u003e\u003cstrong\u003eVisit Our Site\u003c/strong\u003e\u003c/a\u003e or \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://cal.com/brian-hough-pressbox/demo\\\"\u003e\u003cstrong\u003eBook A Demo\u003c/strong\u003e\u003c/a\u003e!\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\",{\"_88\":143,\"_31\":-5,\"_90\":-5,\"_91\":-5,\"_92\":-5,\"_93\":-5,\"_94\":-5},[141],[],\"2025-10-16T00:39:00.000Z\",\"2026-03-22T00:39:49.000Z\",\"2026-03-22T15:35:53.000Z\",[],{\"_31\":79,\"_80\":81,\"_36\":82,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":142},{},\"https://brand-assets.pressbox.studio/019d1603-f108-7999-94e1-1ba4bf2e2243.webp\",\"4d026d4a-5079-4bcb-b38c-1215862e2059\",\"Full-stack Cloudflare Part 3 â Content Orchestration at the Edge\",\"full-stack-cloudflare-part-3-content-orchestration-at-the-edge\",\"https://pressbox.pressboxsites.com/posts/full-stack-cloudflare-part-3-content-orchestration-at-the-edge\",\"\u003cp\u003eThis is part 3/3 of a series of posts about building on Cloudflare. Here is \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://pressbox.studio/blog/full-stack-cloudflare-part-1-building-an-ai-sports-platform-with-d1-drizzle-and-remix\\\"\u003epart 1\u003c/a\u003e and \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://pressbox.studio/blog/full-stack-cloudflare-part-2-unified-content-discovery\\\"\u003epart 2\u003c/a\u003e.\u003c/p\u003e\u003cp\u003eSports fans are impatient and sports content is unpredictable. If youâre building a platform that can simultaneously monitor AND produce coverage for a league, it needs to be fast and reactive. Traditionally, this might involve a process of manually scaling servers up and down, constantly trying to anticipate when a major news story might break. Or if youâre feeling ambitious it could mean managing a complicated Kafka or Kubernetes setup. At PressBox, we side-stepped both approaches by building a content pipeline on the edge leveraging Cloudflare Workers, Queues, and Workflows.\u003c/p\u003e\u003ch2\u003eWhy?\u003c/h2\u003e\u003ch3\u003eThe Old Way Wasnât Working\u003c/h3\u003e\u003cp\u003eWhy build on Cloudflare Workers instead of just spinning up an EC2 instance? The typical setup is familiar: deploy to AWS us-east-1 (\u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://blog.pragmaticengineer.com/aws-outage-us-east-1/\\\"\u003ecrossing your fingers\u003c/a\u003e), set up your database in the same region, maybe add a CDN for static assets. This works fine for predictable and steady traffic patterns or for workloads that are specific and have known constraints.\u003c/p\u003e\u003cp\u003eBut as I mentioned in the intro, sports traffic is weird. You might cruise along at baseline for weeks or months, then suddenly the playoffs (or \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://www.espn.com/blog/truehoop/post/_/id/17853/lebron-james-decision-the-transcript\\\"\u003eThe Decision\u003c/a\u003e) hit and youâre dealing with 10x normal load. With traditional infrastru
135cture, you either overprovision (and waste money) or underprovision (and crash during the biggest moments).\u003c/p\u003e\u003cp\u003eEdge computing isnât new, but it still seems underutilized and/or misunderstood by many tech companies. The gravity to run a traditional server farm is strong, especially if the code running on your servers requires a specific environment. But if youâre comfortable with JavaScript (everyone has to include it somewhere in their stack anyway) then it opens up so many opportunities. It allows us to not think about traditional servers anymore. Traffic spike during the World Cup final? The edge handles it. Quiet Tuesday afternoon? Weâre not paying for idle servers. Each tenant on our platform has wildly different traffic patterns, and the edge just⦠deals with it.\u003c/p\u003e\u003ch3\u003eWorkflows\u003c/h3\u003e\u003cp\u003eWe found a lot of utility from Cloudflare Workflows. Regular workers are meant for short \u0026#x26; specific tasks. Thatâs fine for serving content, but AI processing takes longer. Workflows can run for minutes/hours/days, survive restarts, and coordinate between different services. Without workflows, weâd be building our own job queue system, implementing retry logic, handling state management across failures. Workflows handle all of that for us.\u003c/p\u003e\u003ch2\u003eHow?\u003c/h2\u003e\u003cp\u003eWe broke our system into six specialized workers. Each one does one thing well, and they communicate through queues and service bindings. Hereâs the flow:\u003c/p\u003e\u003cp\u003eIngestion â AI Enrichment â Curation â Scoring â Notifications â Publishing\u003c/p\u003e\u003cp\u003eLetâs walk through each stage.\u003c/p\u003e\u003ch3\u003eStage 1: Getting Content In\u003c/h3\u003e\u003cp\u003eFirst challenge: monitoring content from everywhere. News sites, social media, video platforms, RSS feeds. Some sources publish constantly, others update weekly. Each has its own format and quirks.\u003c/p\u003e\u003cp\u003eWe run a scheduler that checks each source on a custom interval. When itâs time to check a source, we drop a message in a queue:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-json\\\"\u003e{\\n org: \\\"premier-league\\\",\\n sourceId: \\\"bbc-sport\\\",\\n type: \\\"rss\\\"\\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe ingestion worker grabs these messages in batches and processes them:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003eexport default {\\n async queue(batch, env) {\\n for (const message of batch.messages) {\\n try {\\n await processSource(message.body);\\n message.ack(); // Done, remove from queue\\n } catch (error) {\\n // Network error? Retry later\\n \\n if (isTemporary(error)) {\\n message.retry({ delaySeconds: 60 });\\n } else {\\n // Bad config? 404? Don't retry\\n message.ack(); // Give up\\n }\\n }\\n }\\n },\\n};\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eBe pragmatic: retry the transient timeout, fail fast on 404.\u003c/p\u003e\u003cp\u003eWe dump raw content into R2 so downstream workers can process it without hitting the original source again.\u003c/p\u003e\u003ch3\u003eStage 2: Making Content Smart with AI\u003c/h3\u003e\u003cp\u003eRaw HTML isnât super useful. We need structured data: headlines, summaries, entities, sentiment. This is where AI comes in and workflows become essential.\u003c/p\u003e\u003cp\u003eWorkflows let us break AI processing into steps. If one step fails, we retry just that step, not the whole process:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003eclass EnrichmentWorkflow extends WorkflowEntrypoint {\\n async run(event, step) {\\n const { contentId } = event.payload;\\n \\n // Get the content\\n const content = await step.do(\\\"fetch\\\", async () =\u003e {\\n return await fetchContent(contentId);\\n });\\n \\n // Check if we've seen this before\\n const cached = await step.do(\\\"cache-check\\\", async () =\u003e {\\n return await checkCache(content.url);\\n });\\n \\n if (cached) {\\n return cached;\\n }\\n \\n // Run AI enrichment\\n const enriched = await step.do(\\\"ai-process\\\", async () =\u003e {\\n return await runAI(content);\\n });\\n \\n // Save for next time\\n await step.do(\\\"cache-save\\\", async () =\u003e {\\n await saveCache(content.url, enriched);\\n });\\n \\n return enriched;\\n }\\n}
135\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eEach step gets automatic retries and checkpointing. If the AI call times out, we retry just that step. The workflow picks up where it left off.\u003c/p\u003e\u003ch3\u003eStage 3: Human-in-the-Loop Curation\u003c/h3\u003e\u003cp\u003eAI is good but not perfect. We involve human editors who can review and approve content before it goes live. We built a curation interface that lets them:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003eApprove or reject AI-generated summaries\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eFix entity extraction mistakes\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eAdjust relevance scores\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eSet publishing schedules\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eThe curation worker handles all the CRUD operations for this interface, storing decisions that feed back into our ML models. Over time, the system learns what each organization considers publishable.\u003c/p\u003e\u003ch3\u003eStage 4: Scoring What Matters\u003c/h3\u003e\u003cp\u003eA trade rumor about a star player might be huge news for one league but irrelevant to another. We run tenant-specific ML models that score content based on:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003eCategory relevance\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eSource reputation\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eHow fresh the news is\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eHistorical engagement patterns\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eScores can influence everything from homepage placement to which stories make it into email digests.\u003c/p\u003e\u003ch3\u003eStage 5 \u0026#x26; 6: Getting Content Out\u003c/h3\u003e\u003cp\u003eThe last two workers handle distribution. We can send alerts to editors, generate email digests, publish audio, or trigger a push notification. The only limit is the imagination of the league or sports organization weâre working with. All customizable based on their scheduling needs.\u003c/p\u003e\u003ch2\u003eWorker Communication\u003c/h2\u003e\u003cp\u003eWe use three communication patterns:\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eQueues for async work\u003c/strong\u003e: When worker Aâs output becomes worker Bâs input, we use a queue. Decouples the workers, buffers traffic spikes, gives us automatic retries.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eService bindings for sync calls\u003c/strong\u003e: When we need an immediate response (like fetching config), we use service bindings. These are basically RPC calls that stay within Cloudflareâs network.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eWorkflows for orchestration\u003c/strong\u003e: Multi-step processes where each step might fail independently? Thatâs workflow territory.\u003c/p\u003e\u003ch2\u003eMaking Multi-Tenancy Work\u003c/h2\u003e\u003cp\u003eAll of our customers get complete data isolation. We built tenant-scoped APIs that dynamically connect to the right database:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\\\"language-javascript\\\"\u003efunction getContentAPI(env, org) {\\n // Each org has their own database\\n const dbUrl = env[`DB_${org.toUpperCase()}`];\\n \\n return {\\n async getContent(id) {\\n const db = createClient(dbUrl);\\n return await db.query(\\\"SELECT * FROM content WHERE id = ?\\\", id);\\n }\\n };\\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eSame pattern for vector stores, ML models, everything. Strong isolation without complex filtering logic everywhere.\u003c/p\u003e\u003ch2\u003eOur Learnings\u003c/h2\u003e\u003cp\u003eWorkflows \u0026#x26; Queues were the answer to many problems weâve faced over time. As we built the platform, we ended up in several situations that didnât scale or work over time:\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eSynchronous worker chains\u003c/strong\u003e: This is a very common pattern when building with workers. Worker A calls Worker B calls Worker C. Whenever we notice this happening we can quickly eject and just drop something in a queue or kick off a workflow.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eThe Super Worker\u003c/strong\u003e: Another common pattern is to cram everything into one giant worker. This is feasible now using frameworks that run comfortably in a worker like Hono or React Router. But we prefer purpose-built workers that can be deployed independently. It also helps with cold-starts.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eObservability\u003c/strong\u003e: You canât just SSH into a server and tail logs. Cloudflare does have an Observability dashboard, but we havenât found it very reliable. Especially for real-time stuff. So weâve had to be a little creative with structured logging, and custom metrics/events. Sentry and PostHog have been great for this.\u003c/p\u003e\u003ch2\u003eConclusion\u003c/h2\u003e\u003cp\u003eWe know this type of infrastru
135cture isnât for everyone. There is comfort in the traditional approach of spinning servers up and down and fiddling with CPU and RAM. It also doesnât work if youâre not comfortable writing almost everything in JavaScript/TypeScript. We still have specialized needs that require this traditional approach. But that has been the exception, not the rule.\u003c/p\u003e\u003cp\u003eBut this approach has paid off for us. Our infrastructure costs are low and weâre able to focus on what really matters â building quickly and improving the experience for our customers.\u003c/p\u003e\u003cp\u003eWant to see this in action? \u003ca target=\\\"_blank\\\" rel=\\\"noopener ugc nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer cg qm\\\" href=\\\"https://cal.com/brian-hough-pressbox/demo\\\"\u003e\u003cstrong\u003eBook a demo\u003c/strong\u003e\u003c/a\u003e to check out how PressBox handles content for professional sports organizations.\u003c/p\u003e\",{\"_88\":162,\"_31\":-5,\"_90\":163,\"_91\":163,\"_92\":-5,\"_93\":-5,\"_94\":-5},[157],[],\"2025-10-28T00:45:00.000Z\",\"2026-03-22T00:42:46.000Z\",\"2026-03-23T01:47:45.
135000Z\",8,[],{\"_31\":158,\"_80\":159,\"_36\":160,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":161},\"e5000053-bfb6-43f1-8c15-0ec5b3197ee4\",\"Tory Briggs\",\"tory-briggs\",{},\"https://brand-assets.pressbox.studio/019d1606-9b5f-7cc9-a193-0d71bfd6252b.webp\",\"ChatGPT doing itâs best Cloudflare\",\"53b68240-d19e-4a8e-aaca-dc04b356f54f\",\"Feature Friday - March 27th, 2026\",\"feature-friday-march-27th-2026\",\"https://pressbox.pressboxsites.com/posts/feature-friday-march-27th-2026\",\"\u003cp\u003e\u003cem\u003eFeature Friday\u003c/em\u003e is your weekly look into what's new and coming soon to the \u003cstrong\u003ePressBox\u003c/strong\u003e platform.\u003c/p\u003e\u003ch2\u003ePost Automations In Workflows\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d2599-fc5a-7dd8-ac77-35fd91a9a6d7.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003ePressBox Workflows\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e\u003cem\u003eWorkflows\u003c/em\u003e\u003c/strong\u003e\u003cem\u003e \u003c/em\u003ecan now handle the full publishing lifecycle for your posts. Add a \u003cem\u003ePublish Post \u003c/em\u003eaction to any workflow to automate when and how content goes live. Whether you're simply scheduling a post or coordinating complex event coverage, \u003cem\u003eWorkflows\u003c/em\u003e now integrate directly with your CMS!\u003c/p\u003e\u003ch2\u003eAudio Embeds In Posts\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d259f-a7da-755c-9738-70155c0a1f7e.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eAudio Embeds In Composer\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e\u003cem\u003eComposer\u003c/em\u003e\u003c/strong\u003e now support audio embeds.\u003cstrong\u003e\u003cem\u003e \u003c/em\u003e\u003c/strong\u003eDrop in a SoundCloud or Spotify link using the slash command or block palette, and PressBox renders a clean, inline player right in your posts. Embeds are resolved server-side, so they carry through to your blog, email, and anywhere else you distribute content.\u003c/p\u003e\u003ch2\u003e\u003cstrong\u003eDynamic Brand Colors \u0026#x26; Logos\u003c/strong\u003e\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d259e-abfa-7dd8-ac77-40e7c74c9afd.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eDynamic Brand Assets\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003eBrand Settings got a big glow up this week! Add, remove, and rename color slots, organize logos into custom groups with variants, and pick a preferred color display. Every color and logo in PressBox now adapts to how your brand actually works.\u003c/p\u003e\u003ch2\u003eComing Soon...\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d25a1-8d75-755c-a95c-db3c21dea985.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003ePressBox Composer\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003eLast week, we dropped our first tease of our upcoming \u003cstrong\u003eContent Management System, \u003c/strong\u003eand this week we reached a significant milestone: Launching \u003ca target=\\\"_blank\\\" rel=\\\"noopener noreferrer nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer\\\" href=\\\"https://pressbox.studio/blog\\\"\u003e\u003cstrong\u003ePressBox\u003c/strong\u003e\u003c/a\u003e on \u003ca target=\\\"_blank\\\" rel=\\\"noopener noreferrer nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer\\\" href=\\\"https://pressbox.studio/\\\"\u003e\u003cstrong\u003ePressBox\u003c/strong\u003e\u003c/a\u003e! This represents a major step in our vision to provide a full-stack, personalized content creation platform that reaches your fans when and where they are!\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\",{\"_88\":179,\"_31\":-5,\"_90\":180,\"_91\":180,\"_92\":-5,\"_93\"
135:-5,\"_94\":-5},[177],[],\"2026-03-27T12:00:05.446Z\",\"2026-03-25T13:31:36.438Z\",\"2026-03-31 13:09:25\",2,[],{\"_31\":79,\"_80\":81,\"_36\":82,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":178},{},\"https://brand-assets.pressbox.studio/019d2531-7c5f-7991-a491-4f136ea780d1.webp\",\"Feature Friday\",\"14cd2ed5-4fd2-4087-b9e4-2b19d25f1ea2\",\"Feature Friday - April 3rd, 2026\",\"feature-friday-april-3rd-2026\",\"https://pressbox.pressboxsites.com/posts/feature-friday-april-3rd-2026\",\"\u003cp\u003e\u003cem\u003eFeature Friday\u003c/em\u003e is your weekly look into what's new and coming soon to the \u003cstrong\u003ePressBox\u003c/strong\u003e platform. This week, the team was focused on bringing several frequently requested features to our Email builder.\u003c/p\u003e\u003ch2\u003ePersonalized Top Posts\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d49ae-d897-799a-b6b8-76e6bda47135.jpeg\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eTop Posts\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003eAs \u003cstrong\u003eCMS\u003c/strong\u003e development continues with our design partners, we've connected \u003cstrong\u003e\u003cem\u003ePressBox Email\u003c/em\u003e\u003c/strong\u003e with your posts to deliver personalized story selection based on your fan's preferences! Easily offer hyper-personalized emails utilizing your existing content and a single template!\u003c/p\u003e\u003ch2\u003eTikTok Embeds\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d49b3-5376-7bb3-946d-998d3ea99d20.jpeg\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eTikTok Email Embeds\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003eYou can now drop a \u003cstrong\u003eTikTok\u003c/strong\u003e URL into your email using the \u003cem\u003eSocial Block\u003c/em\u003e, and PressBox will automatically screenshot and embed the post with a polished, native look, just like we do for \u003cstrong\u003eX\u003c/strong\u003e, \u003cstrong\u003eInstagram\u003c/strong\u003e, and \u003cstrong\u003eYouTube\u003c/strong\u003e.\u003c/p\u003e\u003ch2\u003eMore Space\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d49b5-fbf6-799a-b6b8-7ec6c1f0bc65.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eSpacer Email Block\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003eLook...not everything is always going to be flashy. But sometimes you just need a bit of space, and our new email \u003cem\u003eSpacer Block\u003c/em\u003e has you covered!\u003c/p\u003e\",{\"_88\":195,\"_31\":-5,\"_90\":180,\"_91\":180,\"_92\":-5,\"_93\":-5,\"_94\":-5},[193],[],\"2026-04-03T12:00:05.140Z\",\"2026-04-01T13:22:52.999Z\",\"2026-04-03 12:02:45\",[],{\"_31\":79,\"_80\":81,\"_36\":82,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":194},{},\"https://licensed-images.pressbox.studio/pressbox/self-licensed/1775049890710.webp?width=800\u0026format=auto\u0026org=pressbox\",\"7c472a2e-d722-4f0d-ad83-4243f8177116\",\"Feature Friday - April 10th, 2026\",\"feature-friday-april-10th-2026\",\"https://pressbox.pressboxsites.com/posts/feature-friday-april-10th-2026\",\"\u003cp\u003e\u003cem\u003eFeature Friday\u003c/em\u003e is your weekly look into what's new and coming soon to the \u003cstrong\u003ePressBox\u003c/strong\u003e platform. This week brings new functionality to \u003cstrong\u003eNewsroom\u003c/strong\u003e, \u003cstrong\u003eWorkflows\u003c/strong\u003e, \u0026#x26; \u003cstrong\u003eEmail\u003c/strong\u003e.\u003c/p\u003e\u003ch2\u003eBreaking News\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d8369-e83a-7ff8-8059-0f4d1a661330.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eBreaking News\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003eNewsroom\u003c/strong\u003e now automatically identifies potential \u003cstrong\u003e\u003cem\u003eBreaking News\u003c/em\u003e\u003c/strong\u003e, not only helping you stay on top of the latest stories, but also be the first in front of fans with the coverage.\u003c/p\u003e\u003ch2\u003eNew Workflow Triggers\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d836a-2d38-7ff8-8059-13de6787984a.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eStory \u0026#x26; Post Triggers\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003eWe introduced two new content triggers for \u003cstrong\u003eWorkflows\u003c/strong\u003e: \u003cstrong\u003e\u003cem\u003eStories\u003c/em\u003e\u003c/strong\u003e \u0026#x26; \u003cstrong\u003e\u003cem\u003ePosts\u003c/em\u003e\u003c/strong\u003e. \u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003cem\u003eStory Triggers\u003c/em\u003e\u003c/strong\u003e let you create automations in reaction to moments like sending \u003cstrong\u003e\u003cem\u003eBreaking News\u003c/em\u003e\u003c/strong\u003e notifications. \u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003cem\u003ePost Triggers\u003c/em\u003e\u003c/strong\u003e let you automate post-publication \u003cstrong\u003eWorkflows\u003c/strong\u003e including\u003cem\u003e social promotion\u003c/em\u003e, \u003cem\u003elanguage translation\u003c/em\u003e, \u0026#x26; \u003cem\u003eaffiliate distribution\u003c/em\u003e.\u003c/p\u003e\u003ch2\u003eMore Sorting Options\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019d836f-0fae-7667-9bba-05c3007a8d60.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eTop Posts\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003eFor outlets covering multiple sports who want to surface a more diverse set of stories in their regular digests, you can now turn on \u003cstrong\u003eRound Robin Sorting\u003c/strong\u003e to better distribute coverage across the leagues a fan follows.\u003c/p\u003e\",{\"_88\":195,\"_31\":-5,\"_90\":180,\"_91\":180,\"_92\":-5,\"_93\"
135:-5,\"_94\":-5},[208],[],\"2026-04-10T08:00:00.000Z\",\"2026-04-12T20:07:13.356Z\",\"2026-04-12 20:48:08\",[],{\"_31\":79,\"_80\":81,\"_36\":82,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":209},{},\"6646eb64-8a3a-4586-94b8-37ea5d55be22\",\"Feature Friday - April 17th, 2026\",\"feature-friday-april-17th-2026\",\"https://pressbox.pressboxsites.com/posts/feature-friday-april-17th-2026\",\"\u003cp\u003e\u003cem\u003eFeature Friday\u003c/em\u003e is your weekly look into what's new and coming soon to the \u003cstrong\u003ePressBox\u003c/strong\u003e platform. This week brings expanded personalization capabilities to \u003cstrong\u003e\u003cem\u003eEmail\u003c/em\u003e\u003c/strong\u003e and more control over notifications and approvals in \u003cstrong\u003e\u003cem\u003eWorkflows\u003c/em\u003e\u003c/strong\u003e.\u003c/p\u003e\u003ch2\u003eAudience Interests\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019da2e0-aedf-7883-890f-78b94f431779.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eAudience Interests\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e\u003cem\u003eInterests\u003c/em\u003e\u003c/strong\u003e allow you to collect audience preferences and leverage them to further personalize content by linking them to \u003cstrong\u003e\u003cem\u003eTopics\u003c/em\u003e\u003c/strong\u003e.\u003c/p\u003e\u003ch2\u003ePersonalized Emails\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019da2e2-3449-7883-890f-86a590a9990d.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eEmail Personalization\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cem\u003eSpeaking of...\u003c/em\u003e\u003cstrong\u003e\u003cem\u003eEmails\u003c/em\u003e\u003c/strong\u003e are now supercharged with the ability to personalize content based on \u003cstrong\u003e\u003cem\u003eInterests\u003c/em\u003e\u003c/strong\u003e. Show and hide content blocks based on \u003cstrong\u003e\u003cem\u003eInterests,\u003c/em\u003e\u003c/strong\u003e or turn on \u003cem\u003eauto-personalization\u003c/em\u003e for \u003cstrong\u003e\u003cem\u003eTop Posts\u003c/em\u003e\u003c/strong\u003e to curate content based on a fan's individual preferences.\u003c/p\u003e\u003ch2\u003eWorkflow Notifications \u0026#x26; Approvals\u003c/h2\u003e\u003cfigure data-block-type=\\\"image\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019da2cc-530d-7ffc-9927-f9152313583d.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eWorkflow Notifications\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003eWe're giving you more control over notifications and approvals by bringing them to \u003cstrong\u003e\u003cem\u003eWorkflows\u003c/em\u003e\u003c/strong\u003e. Now you can control when and where notifications are sent, customize messages, and add approvals to any \u003cstrong\u003e\u003cem\u003eWorkflow\u003c/em\u003e\u003c/strong\u003e.\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\",{\"_88\":224,\"_31\":225,\"_90\":180,\"_91\":180,\"_92\":-5,\"_93\":-5,\"_94\":226},[222],[],\"2026-04-17T09:00:00.000Z\",\"2026-04-17T12:56:11.240Z\",\"2026-04-19 00:01:35\",[],{\"_31\":79,\"_80\":81,\"_36\":82,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":223},{},\"https://licensed-images.pressbox.studio/pressbox/self-licensed/1775049890710.webp?org=pressbox\",\"a8391275-a014-4770-bcd4-648e79940fbe\",\"self_licensed\",\"f8fd987a-1eb2-4fe1-baef-88cfacba25f8\",\"PressBox Raises $2M Seed Funding Led by Relay Ventures\",\"pressbox-raises-dollar2m-seed-funding-led-by-relay-ventures\",\"https://pressbox.pressboxsites.com/posts/pressbox-raises-dollar2m-seed-funding-led-by-relay-ventures\",\"\u003cp\u003e\u003cstrong\u003eBellingham, WA â \u003c/strong\u003e\u003cem\u003eApril 21, 2026\u003c/em\u003e â PressBox, the full-stack content and marketing personalization platform built for sports, media, and entertainment organizations, announced closing of a $2 million Seed round.\u003cem\u003e \u003c/em\u003eThe round was led by prior investors, \u003ca target=\\\"_blank\\\" rel=\\\"noopener noreferrer nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer\\\" href=\\\"https://relay.vc\\\"\u003e\u003cstrong\u003e\u003cu\u003eRelay Ventures\u003c/u\u003e\u003c/strong\u003e\u003c/a\u003e, and includes \u003ca target=\\\"_blank\\\" rel=\\\"noopener noreferrer nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer\\\" href=\\\"https://capitaleleven.com/\\\"\u003e\u003cstrong\u003e\u003cu\u003eCapital Eleven\u003c/u\u003e\u003c/strong\u003e\u003c/a\u003e, \u003ca target=\\\"_blank\\\" rel=\\\"noopener noreferrer nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer\\\" href=\\\"https://paxholdingsltd.com/\\\"\u003e\u003cstrong\u003e\u003cu\u003ePAX Holdings\u003c/u\u003e\u003c/strong\u003e\u003c/a\u003e, \u003ca target=\\\"_blank\\\" rel=\\\"noopener noreferrer nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer\\\" href=\\\"https://www.av.vc/\\\"\u003e\u003cstrong\u003e\u003cu\u003eAlumni Ventures\u003c/u\u003e\u003c/strong\u003e\u003c/a\u003e, and strategic investors such as \u003cstrong\u003eMaryann Turcke \u003c/strong\u003e
135(former COO, NFL), \u003cstrong\u003eShaun Koiner\u003c/strong\u003e (co-CEO, Sporting News), \u003cstrong\u003eKerri Mattioli \u003c/strong\u003e(SVP Media, Sporting News), and \u003cstrong\u003eDave Marks\u003c/strong\u003e (former VP of Engineering, Bleacher Report).\u003c/p\u003e\u003cp\u003ePressBox empowers companies to create personalized, multi-modal experiences utilizing their proprietary agentic technology. In the last year, PressBox has partnered with organizations including \u003cstrong\u003eThe Sporting News\u003c/strong\u003e, \u003cstrong\u003eFanatics,\u003c/strong\u003e \u003cstrong\u003eWorld Surf League,\u003c/strong\u003e \u003cstrong\u003eALT Sports Data\u003c/strong\u003e, and \u003cstrong\u003eThe Curling Group\u003c/strong\u003e to integrate PressBox's agentic technology into operations across editorial, marketing, broadcast, analytics, and social.\u003c/p\u003e\u003cp\u003e\\\"PressBox's progress over the past year has been beyond expectation, and the impact they've had on early partners has been remarkable,\\\" said Relay Ventures Founder \u0026#x26; Partner John Albright. \\\"Relay has long seen the opportunity with emerging leagues and media properties, especially those that invest in technology early. We've already witnessed within our own portfolio how quickly PressBox is proving invaluable in scaling content, marketing, broadcast, and operations.\\\"\u003c/p\u003e\u003cp\u003e\u003cem\u003eâ\u003c/em\u003eMedia organizations are experiencing a foundational shift in how audiences engage with content,â said Brian Hough, Co-Founder \u0026#x26; CEO of PressBox. \\\"As the ecosystem continues to fragment and AI changes how audiences receive information, real-time, personalized experiences are quickly becoming the expectation. Organizations at the forefront are building the systems to support a world where fans control how and when they engage with a brand like never before.\\\"\u003c/p\u003e\u003cp\u003eOne of those organizations is The Sporting News, whose strategic investment underscores a strong belief in the future of hyper-personalized experiences while empowering its staff with tools that enable a greater focus on the human element.\u003c/p\u003e\u003cp\u003eâHaving recently digitally archived our 140-year history of newspapers, magazines, and online content, The Sporting News is uniquely positioned to package our rich legacy with real-time content creation for fans across the world,â said Shaun Koiner, co-CEO of Sporting News Holdings and The Sporting News. âWith 15 editions delivered in seven languages, PressBox enables our team to deliver unmatched context and experiences across all digital touchpoints.â\u003c/p\u003e\u003cp\u003ePressBox is also excited to announce the hiring of Kevin Jackson, who will be leading Editorial Product. Kevin brings over 35 years of experience in sports media, leading organizations at ESPN, FOX Sports, and Cllct.\u003c/p\u003e\u003cp\u003eâFor years, Iâve been chasing the goal of delivering the best personalized content experience for sports fans around the globe,â said Jackson, a four-time National Sports Emmy winner. âIâm excited to join the team at PressBox, which has already added rocket fuel to that mission.â\u003c/p\u003e\u003cp\u003eâTo have a leader of Kevinâs caliber believe in our vision is an incredible vote of confidence in both PressBox and our mission,â Hough said. âKevin brings an unmatched depth of experience that will benefit not only the company, but our customers and their fans.â\u003c/p\u003e\u003cp\u003eThis funding round comes as PressBox expands with new pilot partnerships and targets a general release later in 2026. Funds will be used for hiring across Product, Data, and Engineering, to support expansion into more sports, new modalities, and develop broader publishing capabilities.\u003c/p\u003e\u003ch2\u003e\u003cstrong\u003e\u003cem\u003eAbout PressBox\u003c/em\u003e\u003c/strong\u003e\u003c/h2\u003e\u003cp\u003ePressBox is building the foundation of personalized media, content, and marketing. Rooted in deep industry expertise (\u003cem\u003eBleacher Report, ESPN, Warner Bros., Fox Sports\u003c/em\u003e), PressBox is purpose-built for the future of media and entertainment, accelerating the discovery, creation, and distribution of personalized, multi-modal content experiences, empowering organizations to reach audiences with highly individualized content and marketing at scale. Backed by $2.8M
135in funding from \u003cstrong\u003eRelay Ventures\u003c/strong\u003e, \u003cstrong\u003eCapital Eleven\u003c/strong\u003e, \u003cstrong\u003ePAX Holdings\u003c/strong\u003e, \u003cstrong\u003e43\u003c/strong\u003e, \u003cstrong\u003eProfluence Capital\u003c/strong\u003e, and \u003cstrong\u003eAlumni Ventures\u003c/strong\u003e.\u003c/p\u003e\u003cp\u003eFor more information on PressBox, visit\u003cstrong\u003e \u003c/strong\u003e\u003ca target=\\\"_blank\\\" rel=\\\"noopener noreferrer nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer\\\" href=\\\"https://pressbox.studio\\\"\u003e\u003cstrong\u003e\u003cu\u003ehttps://pressbox.studio\u003c/u\u003e\u003c/strong\u003e\u003c/a\u003e\u003c/p\u003e\u003cp\u003eFor press or inquiries, please contact: \u003ca target=\\\"_blank\\\" rel=\\\"noopener noreferrer nofollow\\\" class=\\\"text-pink-600 underline cursor-pointer\\\" href=\\\"mailto:[email protected]\\\"\u003e\u003cstrong\u003e\u003cu\[email protected]\u003c/u\u003e\u003c/strong\u003e\u003c/a\u003e\u003c/p\u003e\",{\"_88\":242,\"_31\":-5,\"_90\":243,\"_91\":243,\"_92\":-5,\"_93\":-5,\"_94\":-5},[240],[],\"2026-04-21T11:53:58.121Z\",\"2026-04-05T17:16:52.901Z\",\"2026-04-21 11:57:18\",4,[],{\"_31\":79,\"_80\":81,\"_36\":82,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":241},{},\"https://brand-assets.pressbox.studio/019dafe6-a82b-788a-9735-628e20429017.png\",\"PressBox $2M Seed Round\",\"86eee5d2-6169-4650-94dc-84b92541e60c\",\"Feature Friday - May 1st, 2026\",\"feature-friday-may-1st-2026\",\"https://pressbox.pressboxsites.com/posts/feature-friday-may-1st-2026\",\"\u003cfigure data-feature=\\\"true\\\" data-licensed-image-id=\\\"a8391275-a014-4770-bcd4-648e79940fbe\\\" data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://licensed-images.pressbox.studio/pressbox/self-licensed/1775049890710.webp?width=800\u0026org=pressbox#x26;format=auto\u0026#x26;org=pressbox\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eFeature Friday\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cem\u003eFeature Friday\u003c/em\u003e is your weekly look into what's new on the \u003cstrong\u003ePressBox\u003c/strong\u003e platform. The team had a big week shipping major features for both \u003cstrong\u003e\u003cem\u003eEmail \u003c/em\u003e\u003c/strong\u003eand\u003cstrong\u003e\u003cem\u003e Workflows\u003c/em\u003e\u003c/strong\u003e.\u003c/p\u003e\u003ch2\u003eGoogle Fonts Support\u003c/h2\u003e\u003cfigure data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019dee40-d96a-737f-a48a-de327e34369c.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eGoogle Fonts\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e\u003cem\u003eBrand \u0026#x26; Voice \u003c/em\u003e\u003c/strong\u003enow enables you to select from hundreds of \u003cstrong\u003e\u003cem\u003eEmail\u003c/em\u003e\u003c/strong\u003e compatible \u003cstrong\u003eGoogle Fonts\u003c/strong\u003e to ensure your newsletter and marketing emails better align with your brand guidelines.\u003c/p\u003e\u003ch2\u003eWorkflow Webhooks\u003c/h2\u003e\u003cfigure data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019dee41-24b9-77ce-ace2-21e5797a02f5.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eWorkflow Webhooks\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003eWebhooks\u003c/strong\u003e enable you to notify endpoints on first and third-party platforms when a Workflow has successfully run. Use it to \u003cem\u003esync content\u003c/em\u003e, \u003cem\u003esend notifications\u003c/em\u003e, or \u003cem\u003eexecute automations on other platforms\u003c/em\u003e. \u003c/p\u003e\u003ch2\u003eWorkflow Logic Nodes\u003c/h2\u003e\u003cfigure data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019dee41-6d44-7309-ac2f-071ba8eebc90.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eWorkflow Logic Nodes\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e\u003cem\u003eWorkflows\u003c/em\u003e\u003c/strong\u003e\u003cem\u003e became a lot more power with the addition of \u003c/em\u003e\u003cstrong\u003eFilter\u003c/strong\u003e\u003cem\u003e \u003c/em\u003eand\u003cem\u003e \u003c/em\u003e\u003cstrong\u003eBranch\u003c/strong\u003e nodes. \u003cstrong\u003eFilters\u003c/strong\u003e give you more control over when \u003cstrong\u003e\u003cem\u003eWorkflows\u003c/em\u003e\u003c/strong\u003e run, by letting you execute them based on conditions including s\u003cem\u003etory type\u003c/em\u003e, \u003cem\u003econtent tag\u003c/em\u003e, \u0026#x26;
135 more. \u003cstrong\u003eBranches\u003c/strong\u003e enable \u003cstrong\u003e\u003cem\u003eWorkflows\u003c/em\u003e\u003c/strong\u003e with branching logic including using different templates or sending notifications to separate channels based on a stories attributes.\u003c/p\u003e\",{\"_88\":195,\"_31\":225,\"_90\":180,\"_91\":180,\"_92\":-5,\"_93\":-5,\"_94\":226},[256],[],\"2026-05-01T14:35:00.000Z\",\"2026-05-03T13:56:44.341Z\",\"2026-05-22 16:59:38\",[],{\"_31\":79,\"_80\":81,\"_36\":82,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":257},{},\"0310d821-cc99-4ab7-b31e-e58f655ad04c\",\"Building PressBox Workflows\",\"building-pressbox-workflows\",\"https://pressbox.pressboxsites.com/posts/building-pressbox-workflows\",\"\u003ch2 data-headline=\\\"true\\\"\u003eBuilding PressBox Workflows\u003c/h2\u003e\u003cp\u003eA lot of what \u003ca href=\\\"https://pressbox.studio\\\"\u003ePressBox\u003c/a\u003e does for a customer runs by itself. A story clears a quality bar and creates a post, a new post pings a Slack channel, an editor gets pulled in to approve something before it goes out. Setting up which of those things happen and under what conditions used to take lots of bespoke configuration.\u003c/p\u003e\u003cp\u003eOver time, the same kind of requests kept coming up, either from customers or from gaps that we ran into ourselves:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003eNotify a Slack channel when something happens\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eAsk a person to approve a post before it goes out\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eAuto-publish or auto-ignore a story based on its score, its tags, or how it was classified\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eSync a published post to an external CMS\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eCall a customer's webhook\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eUse a different post template depending on a post's content\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch2\u003eTrigger, condition, action\u003c/h2\u003e\u003cp\u003eWe solved the first couple of these the obvious way. Slack notifications became a settings section with a few columns behind it and a branch in the worker that sends them. Auto-publishing by score became another setting, a threshold the curator checked before deciding what to post. Neither was much work on its own, but the requests kept coming as we added other functionality and integrations, and underneath they were all starting to look pretty similar.\u003c/p\u003e\u003cp\u003eEvery one of them boils down to the same three steps. Something happens: a story is created, a post publishes, a scheduled time arrives. Maybe you check a condition: is the score high enough? Does it have a certain tag? Then you do something about it: send a Slack message, create or publish a post, call a webhook. \u003cem\u003eTrigger, condition, action.\u003c/em\u003e\u003c/p\u003e\u003cp\u003eWe could see the rest of the request list coming, and each new ask meant the same skeleton over again: another settings section, another branch in a worker, more code we wrote and owned. When a customer wanted a webhook that fired only for posts with a certain tag, or approvals on one content type but not another, that was us making the change, because the logic lived in our code rather than theirs. We'd be sitting between a customer's idea and it actually running for as long as we kept doing it this way. So rather than build the next one, we built the abstraction that helps build all of them and we gave it to our customers.\u003c/p\u003e\u003ch2\u003eWhat we built\u003c/h2\u003e\u003cp\u003ePressBox Workflows! It's a visual builder: you drag nodes onto a canvas and wire them together. There are trigger nodes for the things that can start a flow (a scheduled time, an event/game, new content, a story, a post), filter and branch nodes for the conditions, and output nodes for the actions (send an email, publish a post, notify Slack, request approval, call a webhook). A workflow is just a graph of those, saved as data and run by a scheduler.\u003c/p\u003e\u003cp\u003eThose old requests are now just arrangements of nodes. The auto-publish rule that used to be a pair of number fields on a settings page takes about a minute to build: a
135story trigger, wired into a filter that checks the score is at least 80, wired into a publish node pointed at your CMS. A Slack ping on every new article is even shorter: a content trigger straight into a Slack node.\u003c/p\u003e\u003cfigure data-type=\\\"image-block\\\"\u003e\u003cimg src=\\\"https://brand-assets.pressbox.studio/019f2307-d989-736e-9b36-952669e3011d.png\\\" alt=\\\"\\\"\u003e\u003cfigcaption\u003eA basic workflow for post creation and publishing based on story score.\u003c/figcaption\u003e\u003c/figure\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003eThe variations with filtering and branching are where the flexibility really shows. If a customer only wants to auto-publish stories tagged \\\"injuries,\\\" that's a second condition on the same filter. If they'd prefer that a person looked at every story with a score between 60â80 before it goes out, that's a branch with an approval node hanging off the lower path. Each of those would have been a change to our code before Workflows, and now it's just the customer dragging in a node. A flow that starts as one toggle's worth of behavior can grow into something a settings page could never have held, and we don't have to ship anything new to support it in PressBox.\u003c/p\u003e\u003ch2\u003eHow it runs\u003c/h2\u003e\u003cp\u003eA workflow is stored as data rather than code. The builder saves what you drew as two lists on the workflow row, its nodes and its edges, so nothing about a particular flow is compiled into the app; it's really just a document that describes what should happen.\u003c/p\u003e\u003cp\u003eRunning one means walking that document. An executor starts at the trigger and follows the edges: filters prune the paths whose conditions fail, branches pick a side, outputs do their work. The output nodes fill in their template variables first, so \u003ccode\u003e{post.headline}\u003c/code\u003e becomes the actual headline before the email or the webhook goes out.\u003c/p\u003e\u003cp\u003eNew use cases stay cheap because the node types are a registry. Each one is a small handler with a schema for its config and an execute function:\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eexport interface WorkflowNodeHandler {\\n readonly id: string;\\n readonly category: NodeCategory;\\n readonly configSchema: z.ZodType; // validates this node's config\\n readonly outputSchema: z.ZodType;\\n execute(params: NodeHandlerParams): Promise\u0026#x3C;NodeExecutionResult\u003e;\\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAdding a capability is as straightforward as writing one of those and registering it:\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eregister(sendEmailNode);\\nregister(publishPostNode);\\nregister(webhookNode);\\n// ...one line per node type\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThere's no new branch threaded through a worker and no schema migration, a capability is a handler and one more line in that list. The config schema earns its keep here too: the same schema that describes a node validates it at save time, which is most of how you keep someone from building a flow that can't run.\u003c/p\u003e\u003ch2\u003eWas it worth it?\u003c/h2\u003e\u003cp\u003eThere is one trade-off worth mentioning. A settings toggle cannot be arranged into something that makes no sense... but a graph definitely can. A flow with no output, a filter that never passes, a branch that quietly drops everything down one side. When we made this transition, the actual work moved out of building the features themselves and into keeping people from building broken graphs, which in practice means validation, sensible defaults, and blocking the save when a workflow won't run properly.\u003c/p\u003e\u003cp\u003eThat trade-off has been worth it for us. The clearest sign is that customers now do things we would never have shipped as standalone features, because no one customer's version was worth the engineering on its own. They put together the flow they want and it runs, without a ticket and without us in the middle of it.\u003c/p\u003e\u003cp\u003eAnd there's more on the way! A settings page grows one toggle at a time, but a builder grows by multiplication: every node we add combines with everything customers have already wired up. When social destinations land, they'll work from day one with every trigger, filter, and approval path already out there. The roadmap for Workflows now boils down to building more node types, which means more things our customers can make happen every day without waiting on us.\u003c/p\u003e\u003chr\u003e\u003cp\u003e\u003cem\u003ePressBox is an AI-powered content platform for media companies, sports leagues, and brands: it monitors the things that matter to you, turns what it finds into coverage, and helps you get it published, workflows and all. If you want to see what that looks like in practice, \u003c/em\u003e\u003ca href=\\\"https://cal.com/brian-hough-pressbox/demo\\\"\u003e\u003cem\u003ebook a demo!\u003c/em\u003e\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\",{\"_88\":273,\"_31\":-5,\"_90\":-5,\"_91\":-5,\"_92\":-5,\"_93\"
135:-5,\"_94\":-5},[271],[],\"2026-07-02T13:41:33.959Z\",\"2026-07-01T21:25:27.584Z\",\"2026-07-02 14:18:28\",6,[],{\"_31\":109,\"_80\":110,\"_36\":111,\"_33\":-5,\"_83\":-5,\"_84\":85,\"_86\":272},{},\"https://brand-assets.pressbox.studio/019f1fa9-7312-769c-9379-df96b5b0d60d.png\",\"posthog\",{\"_276\":277,\"_278\":279},\"featureFlags\",[\"P\",277],\"apiKey\",\"phc_cfE4cms8uWiH4kWeglcb2dQOLNbpM61q78o0mYpJilI\"]\n");</script>
135<!--$-->
135<script>window.__reactRouterContext.streamController.enqueue("P277:[{}]\n");</script>
135<!--$-->
135<script>window.__reactRouterContext.streamController.close();</script>
135<!--/$--><!--/$--><!--/$-->
135<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"13d5c0488e71426bbf6d2cfe2a5b36b2","spa":2}' crossorigin="anonymous"></script>
135 136</body></html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.