<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: John Wilson</title>
    <description>The latest articles on DEV Community by John Wilson (@vuthis).</description>
    <link>https://dev.to/vuthis</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4132212%2F9a76e147-0647-439c-8734-ebb222a03f0b.png</url>
      <title>DEV Community: John Wilson</title>
      <link>https://dev.to/vuthis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vuthis"/>
    <language>en</language>
    <item>
      <title>Screen sharing without screen mirroring: a phone-controlled TV display built on WebSockets and a QR code</title>
      <dc:creator>John Wilson</dc:creator>
      <pubDate>Sat, 19 Sep 2026 00:13:57 +0000</pubDate>
      <link>https://dev.to/vuthis/screen-sharing-without-screen-mirroring-a-phone-controlled-tv-display-built-on-websockets-and-a-qr-7hb</link>
      <guid>https://dev.to/vuthis/screen-sharing-without-screen-mirroring-a-phone-controlled-tv-display-built-on-websockets-and-a-qr-7hb</guid>
      <description>&lt;p&gt;Every meeting room, classroom and church hall has a screen, and every screen has a browser. Yet putting one thing on that screen, a PDF, a few photos, a countdown timer, still means hunting for an HDMI cable or mirroring your whole phone to the room, notifications included.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://vuthis.com" rel="noopener noreferrer"&gt;V U This&lt;/a&gt; to fix that with the smallest possible stack. Here is how it works and what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea: the screen is a dumb client, the phone is the remote
&lt;/h2&gt;

&lt;p&gt;Open &lt;strong&gt;vuthis.com&lt;/strong&gt; on any TV, projector laptop or Raspberry Pi. The page creates a display session and shows a QR code that encodes the full controller URL, plus a short code as a fallback. Scan it with a phone and the phone becomes the remote. Whatever you pick on the phone, the screen shows: a photo slideshow, a PDF with page controls, large text, an announcement, a clock in any time zone, a countdown / count-up / count-to timer, a tally counter or a Wi-Fi QR code.&lt;/p&gt;

&lt;p&gt;Only the chosen content ever reaches the screen. That is the whole point: it is screen &lt;em&gt;sharing&lt;/em&gt; without screen &lt;em&gt;mirroring&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a browser and not an app
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Every smart TV, Chromecast (browser mode), Fire TV (Silk), signage player and projector laptop already has a browser. Zero install on either side.&lt;/li&gt;
&lt;li&gt;No pairing, no same-Wi-Fi requirement, no AirPlay/Miracast compatibility matrix. Works over 4G.&lt;/li&gt;
&lt;li&gt;A QR code is the fastest possible pairing UX. People already know what to do with it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;Boring on purpose: &lt;strong&gt;Node.js + Express&lt;/strong&gt;, &lt;strong&gt;SQLite&lt;/strong&gt; for sessions and pass state, &lt;strong&gt;WebSockets&lt;/strong&gt; for the display ↔ controller channel, &lt;strong&gt;pdf.js&lt;/strong&gt; for documents rendered client-side, Stripe for passes, Postfix/OpenDKIM for magic-link login, everything behind Cloudflare. A CLI installer sets up an Ubuntu VPS end to end, and it can be self-hosted on a private LAN for schools and offices that cannot use cloud tools.&lt;/p&gt;

&lt;p&gt;The display page is deliberately stateless: it subscribes to its session over a WebSocket and renders whatever "scene" JSON arrives (&lt;code&gt;{type:"timer", mode:"countdown", seconds:600, label:"Break"}&lt;/code&gt;). The controller is &lt;em&gt;space-adaptive&lt;/em&gt;: on a phone it shows the essentials, on a tablet or laptop it surfaces previews, queueing and context. Same code, more room, more controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that bit me
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;TV browsers are old.&lt;/strong&gt; Samsung Tizen and LG webOS ship Chromium builds several versions behind. No optional chaining in some, flaky &lt;code&gt;requestFullscreen&lt;/code&gt;. Transpile, and test on a real TV.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screensavers and sleep.&lt;/strong&gt; A display page that goes black after ten minutes is useless. The Wake Lock API helps where supported; otherwise a tiny looping video keeps some TVs awake.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDFs on a 4K screen.&lt;/strong&gt; Rendering with pdf.js at device pixel ratio matters; "fit page" vs "fit width" need to be one tap on the phone, not a zoom gesture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timers must survive reconnects.&lt;/strong&gt; Store the &lt;em&gt;end timestamp&lt;/em&gt;, not the remaining seconds, so a display that drops Wi-Fi and comes back shows the right number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free tiers need limits that feel fair.&lt;/strong&gt; One screen, 60 minutes, 20 photos, one PDF, no account. Paid passes ($5.99 for 24h up to $299.99 a year) add multiple screens, 250 MB storage and an automatic playlist mode that turns a TV into simple digital signage.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Where people actually use it
&lt;/h2&gt;

&lt;p&gt;Teachers put a full-screen countdown timer on the classroom projector and worksheets on the board from a phone. Coworking spaces show the agenda on the meeting-room TV. Reception desks run a digital notice board. Event organisers show the schedule and the guest Wi-Fi as a QR code. Families show phone photos on the living-room TV without a casting device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Open &lt;a href="https://vuthis.com" rel="noopener noreferrer"&gt;vuthis.com&lt;/a&gt; on a screen, scan, show. No sign-up. Feature guides: &lt;a href="https://vuthis.com/show-photos-on-tv" rel="noopener noreferrer"&gt;show photos on a TV&lt;/a&gt;, &lt;a href="https://vuthis.com/display-pdf-on-tv" rel="noopener noreferrer"&gt;display a PDF on a TV&lt;/a&gt;, &lt;a href="https://vuthis.com/full-screen-countdown-timer" rel="noopener noreferrer"&gt;full-screen countdown timer&lt;/a&gt;, &lt;a href="https://vuthis.com/digital-notice-board-on-tv" rel="noopener noreferrer"&gt;digital notice board on a TV&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If it fails on a specific TV browser, I would love to know which one. And if you find it useful, a link from your blog, README or wherever you post helps a bootstrapped two-person team more than you would think.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Elsewhere:&lt;/em&gt; the non-technical version of this story is on Medium, &lt;a href="https://medium.com/@john_36585/screen-mirroring-has-a-privacy-problem-a-qr-code-fixes-it-141b36d594b4" rel="noopener noreferrer"&gt;Screen mirroring has a privacy problem. A QR code fixes it.&lt;/a&gt; The launch announcement is on &lt;a href="https://www.prlog.org/13171611-this-lets-anyone-control-tv-or-meeting-room-screen-from-their-phone-with-no-app-or-cable.html" rel="noopener noreferrer"&gt;PRLog&lt;/a&gt;. We post updates on &lt;a href="https://bsky.app/profile/v-u-this.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt; and &lt;a href="https://mastodon.social/@vuthis" rel="noopener noreferrer"&gt;Mastodon&lt;/a&gt;, and there is a &lt;a href="https://flipboard.com/@johnwilson4kdr/put-it-on-the-big-screen-6d9cfob2y" rel="noopener noreferrer"&gt;Flipboard magazine&lt;/a&gt; of guides.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
