waybetter-for-x/apps/web/x/index.html
2026-10-01 06:01:13 +07:00

739 lines
65 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- seo -->
<meta name="theme-color" content="#07080c" />
<link rel="icon" type="image/png" href="/app-icon.png" />
<script>document.documentElement.classList.add('js');</script>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Geist:wght@300..900&family=Geist+Mono:wght@400;500;600&family=Instrument+Serif:ital@1&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="../src/base.css" />
<link rel="stylesheet" href="../src/style.css" />
</head>
<body>
<a data-i18n="site.common.skipToContent" class="skip" href="#main">Skip to content</a>
<header class="top">
<div class="wrap top-row">
<a class="mark" href="#top">
<img src="/app-icon.png" alt="" class="mark-app" width="30" height="30" />
<span class="mark-name" translate="no"><span class="grad">wayBetter</span> <span class="mark-sub">for X</span></span>
</a>
<nav data-i18n-aria-label="site.common.primary" class="top-nav" aria-label="Primary">
<a href="../" class="keep nav-family">wayBetter</a>
<a data-i18n="site.common.store" href="../store/" class="keep">Store</a>
<a data-i18n="site.x.nav.features" href="#features">Features</a>
<a data-i18n="site.common.themes" href="#themes">Themes</a>
<a data-i18n="site.common.plugins" href="#plugins">Plugins</a>
<a data-i18n="site.x.nav.fixes" href="#fixes">Fixes</a>
<a data-i18n="site.x.nav.makeYourOwn" href="#make">Make your own</a>
<a data-i18n="site.common.faq" href="#faq">FAQ</a>
<a data-i18n="site.common.source" data-i18n-aria-label="site.common.sourceOn" href="%REPO_URL%" class="keep keep-md src-link" aria-label="Source on %FORGE_HOST%"
><img class="src-logo" src="/git-crt-logo.svg" alt="" width="16" height="16" />Source</a
>
</nav>
<!-- lang:top -->
</div>
<div class="top-progress" aria-hidden="true"></div>
</header>
<main id="main">
<!-- HERO -->
<section class="hero" id="top">
<div class="hero-glow" aria-hidden="true"></div>
<div class="wrap hero-inner">
<div class="hero-copy">
<p data-i18n="site.x.top.freeOpenSourceGpl3" class="kicker"><span class="kicker-dot"></span><span class="foss" translate="no">(FOSS)</span> Free &amp; open source &middot; GPL-3.0</p>
<img data-i18n-alt="site.common.waybetterForXLogo" src="/app-icon.png" alt="wayBetter for X logo" class="hero-logo" width="72" height="72" />
<h1 data-i18n="site.x.top.xExtended">X, <em class="grad">extended.</em></h1>
<p data-i18n="site.x.top.theLiveXComIn" class="hero-sub">
The live x.com in a light desktop window: tabs, split panes, every account side by
side, fourteen themes, eight area plugins, a draft vault with history, and fixes for the bugs
X ships. Anyone can make a theme or a plugin for it.
</p>
<div class="ctas hero-ctas">
<a data-i18n="site.common.downloadForWindows" class="btn btn-brush btn-lg" href="../v1/download/windows/latest">
<svg class="icon" viewBox="0 0 16 16" aria-hidden="true" focusable="false">
<path fill="currentColor" d="M0 2.5 6.6 1.6v6H0V2.5Zm7.4-.9L16 0v7.5H7.4v-5.9ZM0 8.5h6.6v6L0 13.6V8.5Zm7.4 0H16V16l-8.6-1.2V8.5Z" />
</svg>
Download for Windows
</a>
<a data-i18n="site.common.sourceOn" data-i18n-aria-label="site.common.sourceOn" class="btn btn-ghost btn-lg src-link" href="%REPO_URL%" aria-label="Source on %FORGE_HOST%">
<img class="src-logo" src="/git-crt-logo.svg" alt="" width="16" height="16" />
Source on %FORGE_HOST%
</a>
</div>
<p data-i18n="site.x.top.windowsNowMacosAndLinux" class="hero-note">Windows, macOS and Linux &middot; updates install silently</p>
</div>
<div class="hero-visual">
<figure class="demo-frame demo-frame--hero">
<video data-i18n-aria-label="site.x.top.waybetterForXInSplit" class="demo-video" autoplay muted loop playsinline preload="metadata" width="1600" height="900"
poster="/demo/hero.webp" aria-label="wayBetter for X in split view: @CRTkafa and @playfishies feeds scrolling side by side, then the theme switching to Classic Twitter and back">
<source src="/demo/hero.mp4" type="video/mp4" />
</video>
</figure>
</div>
</div>
<div class="wrap">
<div class="stats hero-stats">
<div class="stat"><b data-count="14">14</b><span data-i18n="site.x.top.builtInThemes">built-in themes</span></div>
<div class="stat"><b data-count="14">14</b><span data-i18n="site.x.top.bundledPlugins">bundled plugins</span></div>
<div class="stat"><b data-count="9">9</b><span data-i18n="site.x.top.fixesForXSBugs">fixes for X's bugs</span></div>
<div class="stat"><b data-count="36">36</b><span data-i18n="site.x.top.tweaks">tweaks</span></div>
</div>
</div>
</section>
<!-- FEATURE TOUR -->
<section class="section tour" id="features">
<div class="wrap">
<header class="sec-head" data-reveal>
<p data-i18n="site.x.features.tourEverythingInIt" class="chapter"><b>Tour</b> Everything in it</p>
<h2 data-i18n="site.x.features.builtForPeopleWhoLive" class="display">Built for people who <em>live in their timeline.</em></h2>
<p data-i18n="site.x.features.everythingAHeavyXUser" class="lead">
Everything a heavy X user wished the official app shipped with, on the real x.com.
Twelve stops; each one is a real feature you can switch on today.
</p>
</header>
<nav data-i18n-aria-label="site.x.features.featureTour" class="tour-index" aria-label="Feature tour" data-reveal>
<a data-i18n="site.x.features.tabsSplit" href="#tabs"><span>01</span>Tabs &amp; split</a>
<a data-i18n="site.x.features.accounts" href="#accounts"><span>02</span>Accounts</a>
<a data-i18n="site.x.features.links" href="#links"><span>03</span>Links</a>
<a data-i18n="site.x.features.palette" href="#palette"><span>04</span>Palette</a>
<a data-i18n="site.x.features.themes" href="#themes"><span>05</span>Themes</a>
<a data-i18n="site.x.features.plugins" href="#plugins"><span>06</span>Plugins</a>
<a data-i18n="site.x.features.fixes" href="#fixes"><span>07</span>Fixes</a>
<a data-i18n="site.x.features.drafts" href="#drafts"><span>08</span>Drafts</a>
<a data-i18n="site.x.features.tweaks" href="#tweaks"><span>09</span>Tweaks</a>
<a data-i18n="site.x.features.alertsMedia" href="#alerts"><span>10</span>Alerts &amp; media</a>
<a data-i18n="site.x.features.updates" href="#updates"><span>11</span>Updates</a>
<a data-i18n="site.x.features.privacy" href="#privacy"><span>12</span>Privacy</a>
</nav>
</div>
<!-- 01 Tabs & split -->
<article class="pillar" id="tabs">
<div class="wrap pillar-grid">
<div class="pillar-copy" data-reveal>
<p class="pillar-n">01</p>
<h3 data-i18n="site.x.tabs.tabsAndSplitPanes">Tabs and split panes.</h3>
<p data-i18n="site.x.tabs.openProfilesSearchesAndThreads">Open profiles, searches and threads in their own tabs, and put any two side by side. Drag a tab, or any link, to the edge of a pane to split it.</p>
<ul class="ticks">
<li data-i18n="site.x.tabs.splitRightSplitDown">Split right <kbd>Ctrl</kbd> <kbd>\</kbd>, split down <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>\</kbd></li>
<li data-i18n="site.x.tabs.newTabWithShortcutsRecently">New tab <kbd>Ctrl</kbd> <kbd>T</kbd> with shortcuts, recently closed tabs and "Open as" an account</li>
<li data-i18n="site.x.tabs.pinnedTabsAndYourTabs">Pinned tabs, and your tabs and split layout restored on launch</li>
<li data-i18n="site.x.tabs.dropALinkOnA">Drop a link on a pane edge, a tab strip or the window: split, tab or new tab</li>
<li data-i18n="site.x.tabs.oneNavigationInSplitView">One navigation in split view: side-by-side panes of the same account keep X's left rail only once</li>
</ul>
</div>
<div class="pillar-vis" data-reveal style="--d: 1" aria-hidden="true">
<div class="mock-win">
<div class="mw-bar">
<span class="mw-pin"><i class="av a1"></i></span>
<span data-i18n="site.common.home" class="mw-tab on"><i class="av a1"></i>Home</span>
<span class="mw-tab"><i class="av a1"></i>@CRTkafa</span>
<span data-i18n="site.common.search" class="mw-tab"><i class="av a2"></i>Search</span>
<span class="mw-plus">+</span>
</div>
<div class="mw-split">
<div class="mw-pane"><div class="sk"><i></i><b></b><b class="s"></b></div><div class="sk"><i></i><b></b><b class="s"></b></div><div class="sk"><i></i><b></b><b class="s"></b></div></div>
<div class="mw-pane mw-drop"><span data-i18n="site.x.tabs.splitRight" class="drop-label">Split right</span></div>
</div>
<span class="mw-cursor"></span>
</div>
</div>
</div>
</article>
<!-- 02 Accounts -->
<article class="pillar pillar-flip" id="accounts">
<div class="wrap pillar-grid">
<div class="pillar-copy" data-reveal>
<p class="pillar-n">02</p>
<h3 data-i18n="site.x.accounts.everyAccountSideBySide">Every account, side by side.</h3>
<p data-i18n="site.x.accounts.eachAccountLivesInIts">Each account lives in its own profile with its own session, so all of them stay signed in at once. You log in to x.com itself, the normal way.</p>
<ul class="ticks">
<li data-i18n="site.x.accounts.accountsAreReadFromX">Accounts are read from X's own account button, never typed in</li>
<li data-i18n="site.x.accounts.aColoredBadgeOnEvery">A colored badge on every tab's icon says which account it is</li>
<li data-i18n="site.x.accounts.renameAndColorAccountsSee">Rename and color accounts; see how many tabs each one has open</li>
<li data-i18n="site.x.accounts.newTabAsAnyAccount">"New tab as" any account from the palette or the new-tab page</li>
</ul>
</div>
<div class="pillar-vis" data-reveal style="--d: 1" aria-hidden="true">
<div class="mock-menu">
<p data-i18n="site.x.accounts.accounts" class="mm-title">Accounts</p>
<div class="mm-row on"><i class="av a1 lg"></i><div><b translate="no">CRT</b><span>@CRTkafa</span></div><em data-i18n="site.x.accounts.n3Tabs">3 tabs</em></div>
<div class="mm-row"><i class="av a2 lg"></i><div><b translate="no">playfishies</b><span>@playfishies</span></div><em data-i18n="site.x.accounts.n2Tabs">2 tabs</em></div>
<div class="mm-row"><i class="av a3 lg"></i><div><b data-i18n="site.x.accounts.work">Work</b><span>@yourbrand</span></div><em data-i18n="site.x.accounts.n1Tab">1 tab</em></div>
<div data-i18n="site.x.accounts.addAccount" class="mm-add">+ Add account</div>
</div>
</div>
</div>
</article>
<!-- Deck -->
<article class="pillar" id="deck">
<div class="wrap pillar-grid">
<div class="pillar-copy" data-reveal>
<p data-i18n="site.x.deck.new" class="pillar-n">New</p>
<h3 data-i18n="site.x.deck.powerUserModeTheDeck">Deck. <em>The columns are back.</em></h3>
<p data-i18n="site.x.deck.columnsOfXSideBy">Columns of X side by side, TweetDeck-style: Home, Notifications, Mentions, a search, a list or a profile, each in the account you pick. Every column is the real x.com; every like and reply is X's own.</p>
<ul class="ticks">
<li data-i18n="site.x.deck.unreadCountsOnEveryColumn">Unread counts on every column, filters with keywords or regex</li>
<li data-i18n="site.x.deck.andBetweenColumnsAlt1">[ and ] between columns, Alt+1–9 to jump, Ctrl+Alt+N to post from a dock</li>
<li data-i18n="site.x.deck.pagesOfWholeColumnsOff">Pages of whole columns; off-page columns rest in low memory</li>
</ul>
</div>
<div class="pillar-vis" data-reveal style="--d: 1" aria-hidden="true">
<div class="mock-menu">
<p data-i18n="site.x.deck.deck" class="mm-title">Deck</p>
<div class="mm-row on"><i class="av a1 lg"></i><div><b data-i18n="site.common.home">Home</b><span>@CRTkafa</span></div><em data-i18n="site.x.deck.n12New">12 new</em></div>
<div class="mm-row"><i class="av a1 lg"></i><div><b data-i18n="site.x.deck.notifications">Notifications</b><span>@CRTkafa</span></div><em data-i18n="site.x.deck.n3New">3 new</em></div>
<div class="mm-row"><i class="av a2 lg"></i><div><b data-i18n="site.x.deck.mentions">Mentions</b><span>@playfishies</span></div><em data-i18n="site.x.deck.n1New">1 new</em></div>
<div class="mm-row"><i class="av a3 lg"></i><div><b data-i18n="site.common.search">Search</b><span data-i18n="site.x.deck.waybetterLatest">wayBetter · Latest</span></div><em data-i18n="site.x.deck.live">live</em></div>
<div data-i18n="site.x.deck.addColumn" class="mm-add">+ Add column</div>
</div>
</div>
</div>
</article>
<!-- 03 Links -->
<article class="pillar" id="links">
<div class="wrap pillar-grid">
<div class="pillar-copy" data-reveal>
<p class="pillar-n">03</p>
<h3 data-i18n="site.x.links.linksGoWhereYouWant">Links go where you want.</h3>
<p data-i18n="site.x.links.decideOnceWhereLinksOpen">Decide once where links open. "Beside" opens a split next to the pane you clicked in and reuses it for the next link, so reading a thread never loses your timeline.</p>
<ul class="ticks">
<li data-i18n="site.x.links.postsProfilesHashtagsAndLists">Posts, profiles, hashtags and lists: same tab, beside, new tab or system browser</li>
<li data-i18n="site.x.links.otherSitesBesideNewTab">Other sites: beside, new tab or your system browser</li>
<li data-i18n="site.x.links.twitterComLinksLoadOn">twitter.com links load on x.com; X's own "new tab" links stay in the app</li>
</ul>
</div>
<div class="pillar-vis" data-reveal style="--d: 1" aria-hidden="true">
<div class="mock-settings">
<div class="ms-row">
<p data-i18n="site.x.links.linksToXPages">Links to X pages</p>
<div class="seg"><span data-i18n="site.x.links.sameTab">Same tab</span><span data-i18n="site.common.beside" class="on">Beside</span><span data-i18n="site.common.newTab">New tab</span><span data-i18n="site.common.systemBrowser">System browser</span></div>
</div>
<div class="ms-row">
<p data-i18n="site.x.links.linksToOtherSites">Links to other sites</p>
<div class="seg"><span data-i18n="site.common.beside">Beside</span><span data-i18n="site.common.newTab" class="on">New tab</span><span data-i18n="site.common.systemBrowser">System browser</span></div>
</div>
<div class="ms-row">
<p data-i18n="site.x.links.restoreTabsOnLaunch">Restore tabs on launch</p>
<span class="toggle on"></span>
</div>
</div>
</div>
</div>
</article>
<!-- 04 Palette -->
<article class="pillar pillar-flip" id="palette">
<div class="wrap pillar-grid">
<div class="pillar-copy" data-reveal>
<p class="pillar-n">04</p>
<h3 data-i18n="site.x.palette.everythingIsOneKeystrokeAway">Everything is one keystroke away.</h3>
<p data-i18n="site.x.palette.theCommandPaletteFindsAny">The command palette <kbd>Ctrl</kbd> <kbd>K</kbd> finds any open tab, account, setting or X page. Every tab has an address bar that names where you are.</p>
<ul class="ticks">
<li data-i18n="site.x.palette.searchXStraightFromThe">Search X straight from the palette or the address bar</li>
<li data-i18n="site.x.palette.xsSearchOperatorsAs">X's search operators (<code>from:</code>, <code>since:</code>, <code>filter:media</code>, <code>min_faves:</code>…) as chips, in the address bar and under X's own search box</li>
<li data-i18n="site.x.palette.jumpToXSettingsPages">Jump to X settings pages like muted words or blocked accounts; you finish the change on X</li>
</ul>
</div>
<div class="pillar-vis" data-reveal style="--d: 1" aria-hidden="true">
<div class="mock-pal">
<div class="mp-input"><span translate="no">from:CRTkafa filter:media</span><kbd>Esc</kbd></div>
<p data-i18n="site.common.search" class="mp-group">Search</p>
<div data-i18n="site.x.palette.searchXLatestForFrom" class="mp-item on"><i>&#9906;</i>Search X (Latest) for from:CRTkafa filter:media</div>
<p data-i18n="site.x.palette.tabs" class="mp-group">Tabs</p>
<div data-i18n="site.x.palette.homeX" class="mp-item"><i class="av a1"></i>Home / X<small translate="no">x.com/home</small></div>
<p data-i18n="site.x.palette.profiles" class="mp-group">Profiles</p>
<div data-i18n="site.x.palette.newTabAsPlayfishies" class="mp-item"><i class="av a2"></i>New tab as playfishies</div>
<p class="mp-group">wayBetter for X</p>
<div data-i18n="site.x.palette.appearance" class="mp-item"><i>&#9681;</i>Appearance</div>
</div>
</div>
</div>
</article>
<!-- 05 Themes -->
<article class="pillar pillar-wide" id="themes">
<div class="wrap">
<div class="pillar-head" data-reveal>
<p class="pillar-n">05</p>
<h3 data-i18n="site.x.themes.fourteenThemesEveryOneA">Fourteen themes. <em>Every one a full redesign.</em></h3>
<p data-i18n="site.x.themes.aThemeIsMoreThan">A theme is more than colors: fonts, corners, avatar shape, column width, density, cards, backgrounds, hover effects and even a CRT overlay. Contrast is enforced for every theme, built-in or imported, so text stays readable. Pick one, then change any part of it.</p>
</div>
<div class="themes-grid">
<div class="themes-live" data-reveal>
<div class="tp" data-theme-preview>
<div class="tp-col">
<div class="tp-head"><span data-i18n="site.common.home">Home</span><span data-i18n="site.common.post" class="tp-btn">Post</span></div>
<div class="tp-tabs"><span data-i18n="site.common.forYou">For you</span><span data-i18n="site.common.following" class="on">Following</span></div>
<div class="tp-post">
<i class="tp-av"></i>
<div>
<div class="tp-meta" translate="no"><b>wayBetter</b>@CRTkafa &middot; 2m</div>
<p data-i18n="site.x.themes.sameTimelineFourteenWaysPick" class="tp-text">Same timeline, fourteen ways. Pick one, then <a href="#make" tabindex="-1">make your own</a>.</p>
<div class="tp-acts"><span>12</span><span>48</span><span class="liked">&#9829; 101</span></div>
</div>
</div>
<div class="tp-post">
<i class="tp-av"></i>
<div>
<div class="tp-meta" translate="no"><b>playfishies</b>@playfishies &middot; 9m</div>
<p data-i18n="site.x.themes.themesAreJsonImportExport" class="tp-text">Themes are JSON. Import, export, share.</p>
<div class="tp-card"></div>
</div>
</div>
</div>
<span class="tp-name"><i></i><span data-theme-name translate="no">Night Ink</span></span>
</div>
<div data-i18n-aria-label="site.common.previewABuiltInTheme" class="tp-chips" role="group" aria-label="Preview a built-in theme" data-theme-chips></div>
</div>
<ul class="theme-cards" data-reveal style="--d: 1">
<li><button type="button" data-pick-theme="x"><span class="sw"><i style="background:#000"></i><i style="background:#1d9bf0"></i><i style="background:#e7e9ea"></i></span><b translate="no">X default</b><span data-i18n="site.x.themes.xsOwnLookDefault">X's own look: Default, Dim or Lights out.</span></button></li>
<li><button type="button" data-pick-theme="classic"><span class="sw"><i style="background:#c0deed"></i><i style="background:#0077b0"></i><i style="background:#fff"></i></span><b translate="no">Classic Twitter</b><span data-i18n="site.x.themes.n2012OnASkyBlue">2012 on a sky-blue canvas, Helvetica, the old link blue.</span></button></li>
<li><button type="button" data-pick-theme="night-ink"><span class="sw"><i style="background:#07080c"></i><i style="background:#5b8cff"></i><i style="background:#eef0f7"></i></span><b translate="no">Night Ink</b><span data-i18n="site.x.themes.blueBlackAndGeistSoft">Blue-black and Geist, soft corners, a quiet glow.</span></button></li>
<li><button type="button" data-pick-theme="terminal"><span class="sw"><i style="background:#040804"></i><i style="background:#3dff7a"></i><i style="background:#b6f7a8"></i></span><b translate="no">Terminal</b><span data-i18n="site.x.themes.phosphorGreenMonospaceScanlinesAnd">Phosphor green, monospace, scanlines and CRT.</span></button></li>
<li><button type="button" data-pick-theme="paper"><span class="sw"><i style="background:#fbf8f1"></i><i style="background:#a8321f"></i><i style="background:#2a241d"></i></span><b translate="no">Paper</b><span data-i18n="site.x.themes.newsprintCardsASerifReading">Newsprint cards, a serif reading face, ink-red links.</span></button></li>
<li><button type="button" data-pick-theme="dracula"><span class="sw"><i style="background:#282a36"></i><i style="background:#bd93f9"></i><i style="background:#ff79c6"></i></span><b translate="no">Dracula</b><span data-i18n="site.x.themes.purpleLinksPinkButtonsGraphite">Purple links, pink buttons, graphite and a dot grid.</span></button></li>
<li><button type="button" data-pick-theme="nord"><span class="sw"><i style="background:#2e3440"></i><i style="background:#88c0d0"></i><i style="background:#eceff4"></i></span><b translate="no">Nord</b><span data-i18n="site.x.themes.arcticSlateFloatingCardsAn">Arctic slate, floating cards, an aurora glow.</span></button></li>
<li><button type="button" data-pick-theme="tokyo-night"><span class="sw"><i style="background:#1a1b26"></i><i style="background:#7aa2f7"></i><i style="background:#bb9af7"></i></span><b translate="no">Tokyo Night</b><span data-i18n="site.x.themes.indigoAndLavenderAWide">Indigo and lavender, a wide column, a street grid.</span></button></li>
<li><button type="button" data-pick-theme="solarized-light"><span class="sw"><i style="background:#fdf6e3"></i><i style="background:#1d6ea8"></i><i style="background:#073642"></i></span><b translate="no">Solarized Light</b><span data-i18n="site.x.themes.creamAndCyanOnEngineering">Cream and cyan on engineering paper.</span></button></li>
<li><button type="button" data-pick-theme="frutiger-aero"><span class="sw"><i style="background:#d8f0fc"></i><i style="background:#1478c8"></i><i style="background:#0a2638"></i></span><b translate="no">Frutiger Aero</b><span data-i18n="site.x.themes.aGlossy2008SkyBubbles">A glossy 2008 sky, bubbles, glass cards.</span></button></li>
<li><button type="button" data-pick-theme="windows-98"><span class="sw"><i style="background:#008080"></i><i style="background:#c0c0c0"></i><i style="background:#000080"></i></span><b translate="no">Windows 98</b><span data-i18n="site.x.themes.tealDesktopSilverWindowsBevelled">Teal desktop, silver windows, bevelled buttons.</span></button></li>
<li><button type="button" data-pick-theme="vaporwave"><span class="sw"><i style="background:#1a0b31"></i><i style="background:#ff71ce"></i><i style="background:#01cdfe"></i></span><b translate="no">Vaporwave</b><span data-i18n="site.x.themes.sunsetOverANeonGrid">Sunset over a neon grid, wide-tracked type.</span></button></li>
<li><button type="button" data-pick-theme="high-contrast"><span class="sw"><i style="background:#000"></i><i style="background:#ffff00"></i><i style="background:#fff"></i></span><b translate="no">High Contrast</b><span data-i18n="site.x.themes.forLowVisionYellowOn">For low vision: yellow on black, larger type, no motion.</span></button></li>
<li><button type="button" data-pick-theme="midnight-oled"><span class="sw"><i style="background:#000"></i><i style="background:#a78bfa"></i><i style="background:#ededf0"></i></span><b translate="no">Midnight OLED</b><span data-i18n="site.x.themes.trueBlackSoftVioletBig">True black, soft violet, big round corners.</span></button></li>
</ul>
</div>
<div class="anatomy" data-reveal>
<p data-i18n="site.x.themes.whatAThemeCanChange" class="api-title">What a theme can change</p>
<ul>
<li><b translate="no">colors</b><span data-i18n="site.x.themes.pageBackgroundSurfacesBorderText">page, background, surfaces, border, text, muted, accent, buttons</span></li>
<li><b translate="no">font</b><span data-i18n="site.x.themes.uiAndPostTextStacks">UI and post-text stacks, size, weights, tracking, leading</span></li>
<li><b translate="no">shape</b><span data-i18n="site.x.themes.cardAndButtonCornersCircle">card and button corners; circle, rounded or square avatars</span></li>
<li><b translate="no">layout</b><span data-i18n="site.x.themes.columnAndSidebarWidthDensity">column and sidebar width, density, cards, frame</span></li>
<li><b translate="no">background</b><span data-i18n="site.x.themes.glowGradientsSixPatternsOr">glow gradients, six patterns, or your own photo with dimming</span></li>
<li><b translate="no">effects</b><span data-i18n="site.x.themes.motionHoverTintLiftGlow">motion, hover tint / lift / glow, shadows, CRT</span></li>
<li><b translate="no">css</b><span data-i18n="site.x.themes.freeFormCssAppendedLast">free-form CSS, appended last</span></li>
</ul>
<p data-i18n="site.x.themes.importFileDropOrPaste" class="anatomy-note">Import (file, drop or paste) and Export in the Appearance panel. Save any customized look as your own theme. Custom CSS for X applies after the theme, like BetterDiscord's.</p>
</div>
</div>
</article>
<!-- 06 Plugins -->
<article class="pillar pillar-wide" id="plugins">
<div class="wrap">
<div class="pillar-head" data-reveal>
<p class="pillar-n">06</p>
<h3 data-i18n="site.x.plugins.fourteenPluginsInTheBox">Eight area plugins in the box. <em>Room for yours.</em></h3>
<p data-i18n="site.x.plugins.everyBundledPluginShipsSwitched">Compose+, Reader+, Profile+, Chat+, Media+, Search+, Notifications+ and Navigation+ are built in, with a switch for every feature: pick a mode on the first start or turn on what you want in Plugins. None of them sends a request or acts on your account. A few of their features:</p>
</div>
<div class="plug-groups">
<section class="plug-group" data-reveal>
<p data-i18n="site.x.plugins.read" class="pg-name">Read</p>
<div class="plug"><b translate="no">Thread Reader</b><p data-i18n="site.x.plugins.aReadThreadButtonUnrolls">A "Read thread" button unrolls the author's thread into a clean reading view, with copy as Markdown.</p></div>
<div class="plug"><b translate="no">Exact Timestamps</b><p data-i18n="site.x.plugins.n5hBecomes5hSep27">"5h" becomes "5h · Sep 27, 2026, 14:03", in your local time.</p></div>
<div class="plug"><b translate="no">Reading Time</b><p data-i18n="site.x.plugins.n3MinReadOnLong">"3 min read" on long posts and X Articles.</p></div>
<div class="plug"><b translate="no">Focus Mode</b><p data-i18n="site.x.plugins.hidesCountsTrendsAndWho">Hides counts, trends and "Who to follow" while you read. <kbd>Alt</kbd> <kbd>Shift</kbd> <kbd>F</kbd> turns it on and off.</p></div>
</section>
<section class="plug-group" data-reveal style="--d: 1">
<p data-i18n="site.x.plugins.clean" class="pg-name">Clean</p>
<div class="plug"><b translate="no">Muted Regex</b><p data-i18n="site.x.plugins.hidePostsByRegularExpression">Hide posts by regular expression on text, name or @handle, locally. <kbd>Alt</kbd> <kbd>Shift</kbd> <kbd>M</kbd> edits the list.</p></div>
<div class="plug"><b translate="no">Clean Links</b><p data-i18n="site.x.plugins.tCoLinksPointStraight">t.co links point straight at their destination, tracking parameters stripped.</p></div>
<div class="plug"><b translate="no">User Notes</b><p data-i18n="site.x.plugins.privateNotesOnAccountsUnder">Private notes on accounts, under the bio and in hover cards. Never sent anywhere.</p></div>
<div class="plug"><b translate="no">Hide Blue Checks</b><p data-i18n="site.x.plugins.postsFromPaidBlueCheck">Posts from paid blue-check accounts fold into a one-line stub you can open. People you follow stay. <kbd>Alt</kbd> <kbd>Shift</kbd> <kbd>H</kbd> for settings.</p></div>
</section>
<section class="plug-group" data-reveal style="--d: 2">
<p data-i18n="site.x.plugins.write" class="pg-name">Write</p>
<div class="plug"><b translate="no">Copy as Markdown</b><p data-i18n="site.x.plugins.aCopyButtonOnEvery">A copy button on every post: a Markdown quote with images, author, date and link.</p></div>
<div class="plug"><b translate="no">Alt-text Reminder</b><p data-i18n="site.x.plugins.aNudgeWhenImagesIn">A nudge when images in the composer have no description. Never blocks sending.</p></div>
<div class="plug"><b translate="no">Reply Guard</b><p data-i18n="site.x.plugins.asksBeforeYouReplyTo">Asks before you reply to a months-old post, or to someone you don't follow if you want. Nothing is sent for you.</p></div>
<div class="plug"><b translate="no">Emoji Picker</b><p data-i18n="site.x.plugins.opensASearchablePickerWith"><kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>E</kbd> opens a searchable picker with your recent emoji and skin tones. <kbd>:fire:</kbd> shortcodes work in text boxes where X has none.</p></div>
</section>
<section class="plug-group" data-reveal style="--d: 3">
<p data-i18n="site.x.plugins.move" class="pg-name">Move</p>
<div class="plug"><b translate="no">Keyboard Plus</b><p data-i18n="site.x.plugins.onThePostFocusedWith">On the post focused with j/k: <kbd>c</kbd> copy link, <kbd>v</kbd> open media, <kbd>a</kbd> author, <kbd>q</kbd> quoted post.</p></div>
<div class="plug"><b translate="no">Media Grid Focus</b><p data-i18n="site.x.plugins.aProfilesMediaTab">A profile's Media tab fills the window: no right column, tighter gaps.</p></div>
</section>
</div>
</div>
</article>
<!-- 07 Fixes -->
<article class="pillar pillar-wide fixes" id="fixes">
<div class="wrap">
<div class="pillar-head" data-reveal>
<p class="pillar-n">07</p>
<h3 data-i18n="site.x.fixes.xsBugsFixedOn">X's bugs, <em>fixed on your machine.</em></h3>
<p data-i18n="site.x.fixes.waybetterForXRunsOn">wayBetter for X runs on top of the real x.com and patches the frontend bugs that ship with it. Every fix is a switch in Settings, on by default. None of them clicks, posts or follows for you: they only make your own actions land.</p>
</div>
<div class="fix-grid">
<article class="fix-item" data-reveal>
<div>
<h3 data-i18n="site.x.fixes.likesThatMatchTheServer">Likes that match the server</h3>
<p data-i18n="site.x.fixes.clickLikeAFewTimes">Click like a few times fast and X's screen can end in the wrong state: here it showed not liked, 2 likes, while X's server had liked, 3. A quick like and unlike can also leave the count one too high until you refresh. wayBetter sends your likes, reposts, bookmarks and follows one at a time, so the heart, the count and the server all end where your last click did.</p>
<p class="fix-legend"><span data-i18n="site.x.fixes.xOnItsOwn">X on its own</span><span>wayBetter for X</span></p>
</div>
<figure class="demo-frame demo-frame--fix">
<video data-i18n-aria-label="site.x.fixes.eightFastClicksOnThe" class="demo-video" muted loop playsinline preload="none" width="1440" height="720" data-lazy-video
poster="/demo/fix-like.webp?v=3" data-poster-small="../demo/fix-like-m.webp?v=3" aria-label="Eight fast clicks on the like button. On X alone the screen shows not liked, 2 likes, while X's server has liked, 3 likes. With wayBetter for X the screen matches the server after a refresh.">
<source data-src="../demo/fix-like-m.mp4?v=3" media="(max-width: 640px)" type="video/mp4" />
<source data-src="../demo/fix-like.mp4?v=3" type="video/mp4" />
</video>
</figure>
</article>
</div>
<ul class="fix-cards">
<li data-reveal><b data-i18n="site.x.fixes.followButtonsThatSettleRight">Follow buttons that settle right</b><p data-i18n="site.x.fixes.followAndUnfollowGoOut">Follow and unfollow go out one at a time, so the button ends on what you last clicked, not on a stale answer.</p></li>
<li data-reveal style="--d: 1"><b data-i18n="site.x.fixes.keepYourPlaceOnBack">Keep your place on Back</b><p data-i18n="site.x.fixes.goingBackOrSwitchingTimeline">Going back, or switching timeline tabs, returns to the post you were reading instead of the top.</p></li>
<li data-reveal style="--d: 2"><b data-i18n="site.x.fixes.noTimelineJumps">No timeline jumps</b><p data-i18n="site.x.fixes.thePostYouAreReading">The post you are reading stays still when X inserts new posts or media above it.</p></li>
<li data-reveal><b data-i18n="site.x.fixes.seeNewPostsWithoutThe">"See new posts" without the jump</b><p data-i18n="site.x.fixes.theNewPostsLandAbove">The new posts land above the one you are reading instead of throwing you to the top. Works with <kbd>.</kbd> too.</p></li>
<li data-reveal style="--d: 1"><b data-i18n="site.x.fixes.keepYourHomeTab">Keep your Home tab</b><p data-i18n="site.x.fixes.pickedFollowingOrAList">Picked Following or a list? When X switches back to "For you" by itself, it switches back.</p></li>
<li data-reveal style="--d: 2"><b data-i18n="site.x.fixes.followingInTimeOrder">Following in time order</b><p data-i18n="site.x.fixes.theFollowingTabAlwaysShows">The Following tab always shows the newest posts first, even when X switched it to "Popular".</p></li>
<li data-reveal><b data-i18n="site.x.fixes.retryFailedMediaUploads">Retry failed media uploads</b><p data-i18n="site.x.fixes.aFailedVideoOrImage">A failed video or image chunk is sent again, up to 3 times. If it still fails, you're told, instead of the post failing silently.</p></li>
<li data-reveal style="--d: 1"><b data-i18n="site.x.fixes.restoreUnsentText">Restore unsent text</b><p data-i18n="site.x.fixes.lostAReplyToA">Lost a reply to a reload, a closed composer or a navigation? The composer offers to put your saved draft back.</p></li>
<li data-reveal style="--d: 2"><b data-i18n="site.x.fixes.clearASeenNotificationBadge">Clear a seen notification badge</b><p data-i18n="site.x.fixes.aCountYouAlreadySaw">A count you already saw on Notifications stays hidden until it changes. Cosmetic; nothing is marked read.</p></li>
</ul>
</div>
</article>
<!-- 08 Drafts -->
<article class="pillar" id="drafts">
<div class="wrap pillar-grid">
<div class="pillar-copy" data-reveal>
<p class="pillar-n">08</p>
<h3 data-i18n="site.x.drafts.aDraftVaultThatNever">A draft vault that never loses a word.</h3>
<p data-i18n="site.x.drafts.whatYouTypeIntoX">What you type into X's composer is captured into a local vault with its full revision history. It says "Saved" only after the write is committed on your disk.</p>
<ul class="ticks">
<li data-i18n="site.x.drafts.aDraftsButtonInX">A Drafts button in X's composer puts a saved draft back; it never posts for you</li>
<li data-i18n="site.x.drafts.everyRevisionKeptCompareAny">Every revision kept: compare any two and restore one</li>
<li data-i18n="site.x.drafts.searchArchiveAndExportAs">Search, archive and export as JSON</li>
<li data-i18n="site.x.drafts.editsNeverSilentlyOverwriteEach">Edits never silently overwrite each other: a conflict keeps both</li>
</ul>
</div>
<div class="pillar-vis" data-reveal style="--d: 1" aria-hidden="true">
<div class="mock-vault">
<div class="mv-head"><b data-i18n="site.x.drafts.drafts">Drafts</b><span data-i18n="site.x.drafts.searchDrafts" class="mv-search">Search drafts</span></div>
<div class="mv-row on"><b data-i18n="site.x.drafts.launchThreadPart2">Launch thread, part 2</b><span data-i18n="site.x.drafts.reply14Revisions">Reply &middot; 14 revisions</span><em data-i18n="site.x.drafts.saved" class="saved">Saved</em></div>
<div class="mv-row"><b data-i18n="site.x.drafts.quoteTheLikeRace">Quote: the like race</b><span data-i18n="site.x.drafts.quote3Revisions">Quote &middot; 3 revisions</span><em data-i18n="site.x.drafts.n2h">2h</em></div>
<div class="mv-row"><b data-i18n="site.x.drafts.themeShowcase">Theme showcase</b><span data-i18n="site.x.drafts.post7Revisions">Post &middot; 7 revisions</span><em data-i18n="site.x.drafts.yesterday">Yesterday</em></div>
<div class="mv-diff">
<p data-i18n="site.x.drafts.fixesTheBugsInX" class="del">- fixes the bugs in X</p>
<p data-i18n="site.x.drafts.fixesTheBugsXShips" class="add">+ fixes the bugs X ships: likes, drafts, jumps</p>
</div>
</div>
</div>
</div>
</article>
<!-- 09 Tweaks -->
<article class="pillar pillar-wide" id="tweaks">
<div class="wrap">
<div class="pillar-head" data-reveal>
<p class="pillar-n">09</p>
<h3 data-i18n="site.x.tweaks.thirtySixTweaksYourX">Thirty-six tweaks. <em>Your X, your rules.</em></h3>
<p data-i18n="site.x.tweaks.hideWhatYouNeverAsked">Hide what you never asked for, bring back what you miss. Every switch applies live, in every tab.</p>
</div>
<div class="tweak-groups" data-reveal>
<div class="tg"><p data-i18n="site.x.tweaks.branding" class="tg-name">Branding <span>3</span></p><ul><li data-i18n="site.common.waybetterForXLogo">wayBetter for X logo</li><li data-i18n="site.x.tweaks.classicTwitterBird">Classic Twitter bird</li><li data-i18n="site.x.tweaks.tweetAndRetweetWording">"Tweet" and "Retweet" wording</li></ul></div>
<div class="tg"><p data-i18n="site.x.tweaks.timeline" class="tg-name">Timeline <span>4</span></p><ul><li data-i18n="site.x.tweaks.hidePromotedPosts">Hide promoted posts</li><li data-i18n="site.x.tweaks.defaultToFollowing">Default to Following</li><li data-i18n="site.x.tweaks.hideTheForYouTab">Hide the "For you" tab</li><li data-i18n="site.x.tweaks.fullWidthTimeline">Full-width timeline</li></ul></div>
<div class="tg"><p data-i18n="site.x.tweaks.sidebar" class="tg-name">Sidebar <span>9</span></p><ul><li data-i18n="site.x.tweaks.hideTrends">Hide Trends</li><li data-i18n="site.x.tweaks.hideWhoToFollow">Hide Who to follow</li><li data-i18n="site.x.tweaks.hideLiveOnX">Hide Live on X</li><li data-i18n="site.x.tweaks.hideTodaysNews">Hide Today's News</li><li data-i18n="site.x.tweaks.hidePremiumUpsells">Hide Premium upsells</li><li data-i18n="site.x.tweaks.hideExploreTrends">Hide Explore trends</li><li data-i18n="site.x.tweaks.hideRelevantPeople">Hide Relevant people</li><li data-i18n="site.x.tweaks.hideWhoToFollowOn">Hide Who to follow on profiles</li><li data-i18n="site.x.tweaks.hideTheWholeSidebar">Hide the whole sidebar</li></ul></div>
<div class="tg"><p data-i18n="site.x.tweaks.navigation" class="tg-name">Navigation <span>5</span></p><ul><li data-i18n="site.x.tweaks.hidePremium">Hide Premium</li><li data-i18n="site.x.tweaks.hideChat">Hide Chat</li><li data-i18n="site.x.tweaks.hideCommunities">Hide Communities</li><li data-i18n="site.x.tweaks.hideGrok">Hide Grok</li><li data-i18n="site.x.tweaks.oneNavigationInSplitView">One navigation in split view</li></ul></div>
<div class="tg"><p data-i18n="site.x.tweaks.posts" class="tg-name">Posts <span>12</span></p><ul><li data-i18n="site.x.tweaks.hideGrokInPosts">Hide Grok in posts</li><li data-i18n="site.x.tweaks.hideViewCounts">Hide view counts</li><li data-i18n="site.x.tweaks.hideEngagementCounts">Hide engagement counts</li><li data-i18n="site.x.tweaks.hideBookmarkButton">Hide bookmark button</li><li data-i18n="site.x.tweaks.noBoldItalicInPosts">No bold/italic in posts</li><li data-i18n="site.x.tweaks.mediaDownloadButton">Media download button</li><li data-i18n="site.x.tweaks.draftsButtonInTheComposer">Drafts button in the composer</li><li data-i18n="site.x.tweaks.searchOperatorChips">Search operator chips</li><li data-i18n="site.x.tweaks.repliesSortedByRecent">Replies sorted by Recent</li><li data-i18n="site.x.tweaks.fullNumbers1234Not">Full numbers (1,234 not 1.2K)</li><li data-i18n="site.x.tweaks.hideVerifiedBadges">Hide verified badges</li><li data-i18n="site.x.tweaks.hideSubscribeButtons">Hide Subscribe buttons</li></ul></div>
<div class="tg"><p data-i18n="site.x.tweaks.video" class="tg-name">Video <span>3</span></p><ul><li data-i18n="site.x.tweaks.rememberVideoVolume">Remember video volume</li><li data-i18n="site.x.tweaks.disableAutoplay">Disable autoplay</li><li data-i18n="site.x.tweaks.stopVideosAtTheEnd">Stop videos at the end</li></ul></div>
</div>
</div>
</article>
<!-- 10 Alerts & media -->
<article class="pillar pillar-flip" id="alerts">
<div class="wrap pillar-grid">
<div class="pillar-copy" data-reveal>
<p class="pillar-n">10</p>
<h3 data-i18n="site.x.alerts.keywordAlertsAndAMedia">Keyword alerts and a media panel.</h3>
<p data-i18n="site.x.alerts.getADesktopNotificationWhen">Get a desktop notification when a keyword you care about shows up in posts X has already loaded for you. Nothing extra is fetched, and nothing leaves your machine.</p>
<ul class="ticks">
<li data-i18n="site.x.alerts.keywordAlertsAsLocalNotifications">Keyword alerts as local notifications, deduplicated and rate limited</li>
<li data-i18n="site.x.alerts.mediaPanelTheNewestImages">Media panel <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>G</kbd>: the newest images from folders you pick, ready to attach</li>
<li data-i18n="site.x.alerts.optionalClipboardHistoryForImages">Optional clipboard history for images and text (off by default, stays on your device)</li>
<li data-i18n="site.x.alerts.savePhotosVideosAndGifs">Save photos, videos and GIFs from posts in original quality</li>
</ul>
</div>
<div class="pillar-vis" data-reveal style="--d: 1" aria-hidden="true">
<div class="mock-toast">
<div class="mt-note">
<img src="/app-icon.png" alt="" width="36" height="36" loading="lazy" />
<div><b data-i18n="site.x.alerts.keywordWaybetter">Keyword: "waybetter"</b><span data-i18n="site.x.alerts.playfishiesTryingTheNewWaybetter">@playfishies: trying the new waybetter themes tonight…</span></div>
</div>
<div class="mt-gallery"><i></i><i></i><i></i><i></i><i></i><i></i></div>
</div>
</div>
</div>
</article>
<!-- 11 Updates -->
<article class="pillar" id="updates">
<div class="wrap pillar-grid">
<div class="pillar-copy" data-reveal>
<p class="pillar-n">11</p>
<h3 data-i18n="site.x.updates.updatesYouNeverHaveTo">Updates you never have to think about.</h3>
<p data-i18n="site.x.updates.updatesAreSignedAndInstall">Updates are signed and install silently, so a fix for something X broke lands without another installer. When a new version is ready, a chip in the titlebar offers a restart, and your tabs come back.</p>
<ul class="ticks">
<li data-i18n="site.x.updates.signedUpdatesCheckedBeforeThey">Signed updates, checked before they install</li>
<li data-i18n="site.x.updates.aLightNativeWindowOn">A light native window on the system WebView, not another browser bundle</li>
<li data-i18n="site.x.updates.n79MbDownloadWindow">7.9&nbsp;MB download, window up in 0.23&nbsp;s, wayBetter's own code loads in 17&nbsp;ms</li>
<li data-i18n="site.x.updates.windowsTodayMacosAndLinux">Windows, macOS and Linux</li>
</ul>
</div>
<div class="pillar-vis" data-reveal style="--d: 1" aria-hidden="true">
<div class="mock-update">
<span data-i18n="site.x.updates.updateReadyRestart" class="mu-chip"><i></i>Update ready &middot; restart</span>
<div class="mu-bar"><span></span></div>
<p><span data-i18n="site.x.updates.signed" class="tag tag-ok">signed</span> <span data-i18n="site.x.updates.silent" class="tag">silent</span> <span data-i18n="site.x.updates.inTheBackground" class="tag">in the background</span></p>
</div>
</div>
</div>
</article>
<!-- 12 Privacy -->
<article class="pillar pillar-flip" id="privacy">
<div class="wrap pillar-grid">
<div class="pillar-copy" data-reveal>
<p class="pillar-n">12</p>
<h3 data-i18n="site.x.privacy.theRealXComNothing">The real x.com. Nothing in between.</h3>
<p data-i18n="site.x.privacy.youSignInToX">You sign in to x.com itself in a standard web view. Your traffic is not proxied through anyone's server, and wayBetter never posts, follows, deletes or sends DMs on its own.</p>
<ul class="ticks">
<li data-i18n="site.x.privacy.noAnalyticsNoTelemetryOn">No analytics, no telemetry on what you read, post or click</li>
<li data-i18n="site.x.privacy.draftsNotesSettingsAndPlugins">Drafts, notes, settings and plugins stay on your machine</li>
<li data-i18n="site.x.privacy.pluginsYouInstallRunInside">Plugins you install run inside X with page access, like BetterDiscord plugins; install code you trust</li>
</ul>
</div>
<div class="pillar-vis" data-reveal style="--d: 1" aria-hidden="true">
<div class="mock-privacy">
<div data-i18n="site.x.privacy.you" class="mpv-node">You</div>
<div class="mpv-line"><span></span></div>
<div class="mpv-node mpv-x">x.com</div>
<p data-i18n="site.x.privacy.noProxyNoTrackerNo" class="mpv-cap">No proxy. No tracker. No middleman.</p>
</div>
</div>
</div>
</article>
</section>
<!-- MAKE YOUR OWN -->
<section class="section make-own" id="make">
<div class="wrap">
<header class="sec-head center" data-reveal>
<p data-i18n="site.x.make.makeYourOwn" class="chapter"><b>Make</b> Your own</p>
<h2 data-i18n="site.common.anyoneCanMakeThemesAnd" class="display">Anyone can make <em class="grad">themes</em> and <em class="grad">plugins.</em></h2>
<p data-i18n="site.x.make.aThemeIsOneJson" class="lead">
A theme is one JSON file: import it in Appearance. A plugin is one JavaScript file: drop
it into the plugins folder and switch it on. No review queue and no account to use
one. Share the file and anyone can use it, or publish it in the
<a href="../store/">wayBetter Store</a>.
</p>
</header>
<div class="make-cols">
<div class="code" data-reveal>
<div class="code-bar"><span class="dots"><i></i><i></i><i></i></span><span class="file">deep-sea.theme.json</span><button data-i18n="site.common.copy" class="copy-btn" type="button" data-copy-from="theme-json">Copy</button></div>
<pre id="theme-json"><code>{
<span class="tk-p">"name"</span>: <span class="tk-s">"Deep Sea"</span>,
<span class="tk-p">"author"</span>: <span class="tk-s">"@you"</span>,
<span class="tk-p">"mode"</span>: <span class="tk-s">"dark"</span>,
<span class="tk-p">"colors"</span>: { <span class="tk-p">"bg"</span>: <span class="tk-s">"#06141b"</span>, <span class="tk-p">"text"</span>: <span class="tk-s">"#e6f4f1"</span>, <span class="tk-p">"accent"</span>: <span class="tk-s">"#2ee6c5"</span> },
<span class="tk-p">"font"</span>: { <span class="tk-p">"family"</span>: [<span class="tk-s">"Geist"</span>], <span class="tk-p">"scale"</span>: <span class="tk-n">1.02</span> },
<span class="tk-p">"shape"</span>: { <span class="tk-p">"radius"</span>: <span class="tk-n">14</span>, <span class="tk-p">"button"</span>: <span class="tk-n">9999</span>, <span class="tk-p">"avatar"</span>: <span class="tk-s">"rounded"</span> },
<span class="tk-p">"layout"</span>: { <span class="tk-p">"density"</span>: <span class="tk-s">"compact"</span>, <span class="tk-p">"cards"</span>: <span class="tk-k">true</span> },
<span class="tk-p">"background"</span>: { <span class="tk-p">"kind"</span>: <span class="tk-s">"pattern"</span>, <span class="tk-p">"pattern"</span>: <span class="tk-s">"grid"</span>,
<span class="tk-p">"ink"</span>: <span class="tk-s">"#2ee6c5"</span>, <span class="tk-p">"opacity"</span>: <span class="tk-n">0.08</span>, <span class="tk-p">"size"</span>: <span class="tk-n">28</span> },
<span class="tk-p">"effects"</span>: { <span class="tk-p">"hover"</span>: <span class="tk-s">"glow"</span> }
}</code></pre>
</div>
<div class="code" data-reveal style="--d: 1">
<div class="code-bar"><span class="dots"><i></i><i></i><i></i></span><span class="file">copy-quote.plugin.js</span><button data-i18n="site.common.copy" class="copy-btn" type="button" data-copy-from="plugin-js">Copy</button></div>
<pre id="plugin-js"><code><span class="tk-c">/**
* @name Copy Quote
* @description y on a focused post copies "@handle: text".
* @version 1.0.0
* @author @you
*/</span>
<span class="tk-t">module</span>.<span class="tk-t">exports</span> = <span class="tk-k">class</span> <span class="tk-f">CopyQuote</span> {
<span class="tk-f">start</span>() {
<span class="tk-k">const</span> api = <span class="tk-t">window</span>.wayBetter.api;
<span class="tk-k">this</span>.scope = api.<span class="tk-f">scope</span>();
<span class="tk-k">this</span>.scope.<span class="tk-f">onKey</span>((event, post) =&gt; {
<span class="tk-k">if</span> (event.key !== <span class="tk-s">'y'</span> || !post) <span class="tk-k">return</span>;
<span class="tk-k">const</span> t = api.<span class="tk-f">tweet</span>(post);
<span class="tk-k">if</span> (t) api.<span class="tk-f">copyText</span>(<span class="tk-s">`@${</span>t.handle<span class="tk-s">}: ${</span>t.text<span class="tk-s">}`</span>)
.<span class="tk-f">then</span>(() =&gt; api.<span class="tk-f">toast</span>(<span class="tk-s">'Copied'</span>));
});
}
<span class="tk-f">stop</span>() { <span class="tk-k">this</span>.scope.<span class="tk-f">dispose</span>(); }
};</code></pre>
</div>
</div>
<div class="api-row" data-reveal>
<p data-i18n="site.x.make.pluginHelperApi" class="api-title">Plugin helper API</p>
<ul>
<li><code>storage(ns)</code></li><li><code>observe(sel, fn)</code></li><li><code>onRouteChange(fn)</code></li><li><code>onKey(fn)</code></li><li><code>tweet(el)</code></li><li><code>copyText(s)</code></li><li><code>toast(msg)</code></li><li><code>injectCSS(id, css)</code></li><li><code>waitFor(sel)</code></li><li><code>scope()</code></li>
</ul>
</div>
<div class="term make-term" data-reveal>
<div class="term-in">
<div class="code-bar"><span class="dots"><i></i><i></i><i></i></span><span data-i18n="site.x.make.buildAWholeApp" class="file">build a whole app</span></div>
<div class="term-line">
<p class="term-cmd" translate="no"><span class="ps" aria-hidden="true">$</span>npm i <span class="pkg">waybetter</span><span class="caret" aria-hidden="true"></span></p>
<button data-i18n="site.common.copy" data-i18n-aria-label="site.common.copyTheInstallCommandNpm" class="copy-btn" type="button" data-copy="npm i waybetter" aria-label="Copy the install command: npm i waybetter">Copy</button>
</div>
<div class="term-foot"><span data-i18n="site.x.make.theFrameworkBehindThisApp">the framework behind this app</span><span data-i18n="site.common.zeroDependencies">zero dependencies</span><span>GPL-3.0-or-later</span></div>
</div>
</div>
<div class="next-strip" data-reveal>
<div class="ns-logos" aria-hidden="true">
<svg viewBox="0 0 24 24" style="color:#ff0033"><path fill="currentColor" d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" /></svg>
<svg viewBox="0 0 24 24" style="color:#53fc18"><path fill="currentColor" d="M1.333 0h8v5.333H12V2.667h2.667V0h8v8H20v2.667h-2.667v2.666H20V16h2.667v8h-8v-2.667H12v-2.666H9.333V24h-8Z" /></svg>
<svg viewBox="0 0 24 24" style="color:#9146ff"><path fill="currentColor" d="M11.571 4.714h1.715v5.143H11.57zm4.715 0H18v5.143h-1.714zM6 0L1.714 4.286v15.428h5.143V24l4.286-4.286h3.428L22.286 12V0zm14.571 11.143l-3.428 3.428h-3.429l-3 3v-3H6.857V1.714h13.714Z" /></svg>
<svg viewBox="0 0 24 24" style="color:#5865f2"><path fill="currentColor" d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z" /></svg>
</div>
<div>
<h3 data-i18n="site.x.make.xWasFirstBuildThe">X was first. <em>Build the next one.</em></h3>
<p data-i18n="site.x.make.youtubeKickTwitchDiscordAny">YouTube, Kick, Twitch, Discord: any app with a web version could get this same window. None is announced; each is waiting for an adapter.</p>
</div>
<a data-i18n="site.x.make.seeWhatsNext" class="btn btn-brush" href="../#next">
See what's next
<svg class="arrow" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 8h9M8.5 4.5 12 8l-3.5 3.5" /></svg>
</a>
</div>
<p data-i18n="site.x.make.youtubeKickTwitchAndDiscord" class="tm-note">YouTube, Kick, Twitch and Discord are trademarks of their respective owners. wayBetter is not affiliated with any of them.</p>
</div>
</section>
<!-- FOSS -->
<section class="section foss-sec" id="foss">
<div class="wrap">
<p data-i18n="site.x.foss.fossFreeAndOpenSource" class="chapter" data-reveal><b>FOSS</b> Free and open source</p>
<p class="foss-giant" aria-hidden="true" data-reveal>(<span>FOSS</span>)</p>
<h2 data-i18n="site.x.foss.noPaidTierNoAds" class="title" data-reveal>No paid tier. No ads. <em>Every line public.</em></h2>
<ol class="manifesto">
<li data-reveal><span class="n">i.</span><h3 data-i18n="site.common.free">Free</h3><p data-i18n="site.x.foss.completelyFreeNoPaidTier">Completely free. No paid tier, no ads, no upsell.</p></li>
<li data-reveal style="--d: 1"><span class="n">ii.</span><h3 data-i18n="site.common.open">Open</h3><p data-i18n="site.x.foss.gpl30OrLater">GPL-3.0-or-later. The app and the framework are public source on %FORGE_HOST%.</p></li>
<li data-reveal style="--d: 2"><span class="n">iii.</span><h3 data-i18n="site.common.private">Private</h3><p data-i18n="site.x.foss.noAnalyticsNoTelemetryOn">No analytics, no telemetry on what you read or post.</p></li>
<li data-reveal style="--d: 3"><span class="n">iv.</span><h3 data-i18n="site.common.yours">Yours</h3><p data-i18n="site.x.foss.forkItThemeItWrite">Fork it, theme it, write plugins. The license keeps it open.</p></li>
</ol>
<div class="foss-links" data-reveal>
<a data-i18n="site.common.sourceOn" data-i18n-aria-label="site.common.sourceOn" class="btn btn-ghost src-link" href="%REPO_URL%" aria-label="Source on %FORGE_HOST%">
<img class="src-logo" src="/git-crt-logo.svg" alt="" width="16" height="16" />
Source on %FORGE_HOST%
</a>
<a data-i18n="site.common.madeByCrtkafa" class="btn btn-ghost" href="https://x.com/CRTkafa">Made by @CRTkafa</a>
</div>
</div>
</section>
<!-- FAQ -->
<section class="section section-tight faq" id="faq">
<div class="wrap wrap-narrow">
<header class="sec-head" data-reveal>
<p data-i18n="site.x.faq.faqFrequentlyAsked" class="chapter"><b>FAQ</b> Frequently asked</p>
<h2 data-i18n="site.x.faq.questionsAnswered" class="title">Questions, <em>answered.</em></h2>
</header>
<div class="faq-list">
<details class="faq-item" open>
<summary data-i18n="site.common.isItSafe">Is it safe?</summary>
<p data-i18n="site.x.faq.waybetterForXLoadsThe">wayBetter for X loads the real x.com in a standard web view and only patches the frontend. It doesn't proxy your traffic through a third-party server or collect your data. Plugins you add yourself run with access to the page, so install only code you trust.</p>
</details>
<details class="faq-item">
<summary data-i18n="site.x.faq.isItFree">Is it free?</summary>
<p data-i18n="site.x.faq.yesWaybetterForXIs">Yes. wayBetter for X is completely free, with no paid tier, ads, or upsells.</p>
</details>
<details class="faq-item">
<summary data-i18n="site.x.faq.isItOpenSource">Is it open source?</summary>
<p data-i18n="site.x.faq.yesLicensedUnderGpl3">Yes, licensed under GPL-3.0. The full source is on <a href="%REPO_URL%">%FORGE_HOST%</a>, and the framework it is built on is <a href="https://www.npmjs.com/package/waybetter">waybetter on npm</a>.</p>
</details>
<details class="faq-item">
<summary data-i18n="site.x.faq.doesItUseTheReal">Does it use the real x.com?</summary>
<p data-i18n="site.x.faq.yesYouSignInTo">Yes. You sign in to x.com exactly as you would in a browser; wayBetter just gives that page a better shell and fixes its frontend bugs.</p>
</details>
<details class="faq-item">
<summary data-i18n="site.x.faq.willItEverPostLike">Will it ever post, like or follow for me?</summary>
<p data-i18n="site.x.faq.noItNeverPostsFollows">No. It never posts, follows, deletes or sends messages by itself. The fixes only make sure your own clicks land the way you meant them.</p>
</details>
<details class="faq-item">
<summary data-i18n="site.x.faq.canIMakeMyOwn">Can I make my own theme or plugin?</summary>
<p data-i18n="site.x.faq.yesThemesAreJsonFiles">Yes. Themes are JSON files you import in the Appearance panel; plugins are <code>*.plugin.js</code> files you drop into the plugins folder. See <a href="#make">Make your own</a>.</p>
</details>
<details class="faq-item">
<summary data-i18n="site.x.faq.whatAboutMacosAndLinux">What about macOS and Linux?</summary>
<p data-i18n="site.x.faq.windowsIsAvailableNowMacos">Windows, macOS and Linux, all three available now.</p>
</details>
<details class="faq-item">
<summary data-i18n="site.x.faq.doesItCollectMyData">Does it collect my data?</summary>
<p data-i18n="site.x.faq.noThereIsNoAnalytics">No. There is no analytics or telemetry collecting what you post, read, or click.</p>
</details>
</div>
</div>
</section>
<!-- CLOSER -->
<section class="closer">
<div class="wrap closer-inner" data-reveal>
<img src="/app-icon.png" alt="" width="96" height="96" class="closer-icon" loading="lazy" />
<h2 data-i18n="site.x.closer.xTheWayItShould" class="display">X, <em class="grad">the way it should work.</em></h2>
<div class="ctas closer-ctas">
<a data-i18n="site.common.downloadForWindows" class="btn btn-brush btn-lg" href="../v1/download/windows/latest">
<svg class="icon" viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path fill="currentColor" d="M0 2.5 6.6 1.6v6H0V2.5Zm7.4-.9L16 0v7.5H7.4v-5.9ZM0 8.5h6.6v6L0 13.6V8.5Zm7.4 0H16V16l-8.6-1.2V8.5Z" /></svg>
Download for Windows
</a>
<a data-i18n="site.x.closer.moreFromWaybetter" class="btn btn-ghost btn-lg" href="../">
More from wayBetter
<svg class="arrow" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 8h9M8.5 4.5 12 8l-3.5 3.5" /></svg>
</a>
</div>
</div>
</section>
</main>
<footer class="foot">
<div class="wrap foot-row">
<a class="mark mark-sm" href="#top">
<img src="/app-icon.png" alt="" width="22" height="22" class="foot-icon" loading="lazy" />
<span class="mark-name" translate="no">wayBetter for X</span>
</a>
<p data-i18n="site.common.licensedUnderGpl30" class="foot-legal">
Licensed under GPL-3.0. Not affiliated with, endorsed by, or sponsored by X Corp.
</p>
<nav data-i18n-aria-label="site.common.footer" class="foot-nav" aria-label="Footer">
<a href="../">wayBetter</a>
<a data-i18n="site.common.store" href="../store/">Store</a>
<a data-i18n="site.common.source" data-i18n-aria-label="site.common.sourceOn" class="src-link" href="%REPO_URL%" aria-label="Source on %FORGE_HOST%"><img class="src-logo" src="/git-crt-logo.svg" alt="" width="16" height="16" />Source</a>
<a data-i18n="site.common.faq" href="#faq">FAQ</a>
<a href="https://x.com/CRTkafa">@CRTkafa</a>
</nav>
<!-- lang:foot -->
</div>
</footer>
<script type="module" src="../src/main.ts"></script>
</body>
</html>