Skip to content

Commit 46abc13

Browse files
creationsofm7claude
andcommitted
docs: add no-scroll typewriter landing page for GitHub Pages
Single-viewport landing page (docs/index.html) for SEO + conversion: - Keyword-led H1, copywriting-skill "letter" body, strong download CTA pinned to the v0.1.1 release exe - Full SEO head: title, meta description, canonical, Open Graph/Twitter, plus SoftwareApplication + FAQPage JSON-LD (validated) - Editorial design: Fraunces + Courier Prime, animated SVG neon highlighter, typewriter reveal, faint paper grain; black on white - No-scroll on desktop; falls back to scroll on phones/short screens Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 9d2edd6 commit 46abc13

1 file changed

Lines changed: 289 additions & 0 deletions

File tree

docs/index.html

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
7+
<!-- ── Primary SEO ───────────────────────────────────────────── -->
8+
<title>Control Your PC From Your Phone — LocalTV Remote (Free)</title>
9+
<meta name="description" content="LocalTV Remote turns your phone into a wireless mouse, keyboard and volume control for any Windows 10/11 PC over Wi-Fi. Free, open-source, no app to install on your phone." />
10+
<!-- TODO: swap this for your custom domain once Pages is wired (e.g. https://localtvremote.com/) -->
11+
<link rel="canonical" href="https://creationsofm7.github.io/localtv-remote/" />
12+
<meta name="robots" content="index, follow" />
13+
<meta name="theme-color" content="#ffffff" />
14+
<meta name="author" content="Mudit Pandey" />
15+
16+
<!-- ── Open Graph / Twitter ──────────────────────────────────── -->
17+
<meta property="og:type" content="website" />
18+
<meta property="og:site_name" content="LocalTV Remote" />
19+
<meta property="og:title" content="Control your Windows PC from your phone — LocalTV Remote" />
20+
<meta property="og:description" content="A free, open-source wireless mouse, keyboard & volume remote for Windows. Install on the PC only — your phone just opens a web page. LAN-only, no account." />
21+
<meta property="og:url" content="https://creationsofm7.github.io/localtv-remote/" />
22+
<!-- TODO: replace with a purpose-made 1200×630 social card -->
23+
<meta property="og:image" content="https://raw.githubusercontent.com/creationsofm7/localtv-remote/main/assets/icon.png" />
24+
<meta name="twitter:card" content="summary_large_image" />
25+
<meta name="twitter:title" content="Control your Windows PC from your phone — LocalTV Remote" />
26+
<meta name="twitter:description" content="Free, open-source phone-as-remote for Windows. Wireless mouse, keyboard & volume over Wi-Fi. No app to install on your phone." />
27+
<meta name="twitter:image" content="https://raw.githubusercontent.com/creationsofm7/localtv-remote/main/assets/icon.png" />
28+
29+
<!-- ── Favicon (inline, no extra request) — a blinking-cursor mark ─ -->
30+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23fff'/%3E%3Crect x='9' y='6' width='5' height='20' fill='%23111'/%3E%3Crect x='17' y='15' width='9' height='6' fill='%23ccff00'/%3E%3C/svg%3E" />
31+
32+
<!-- ── Fonts: distinctive serif display + true typewriter body ──── -->
33+
<link rel="preconnect" href="https://fonts.googleapis.com" />
34+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
35+
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime:ital,wght@0,400;0,700;1,400&family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600&display=swap" rel="stylesheet" />
36+
37+
<!-- ── Structured data: app + FAQ ────────────────────────────── -->
38+
<script type="application/ld+json">
39+
{
40+
"@context": "https://schema.org",
41+
"@type": "SoftwareApplication",
42+
"name": "LocalTV Remote",
43+
"operatingSystem": "Windows 10, Windows 11",
44+
"applicationCategory": "UtilitiesApplication",
45+
"description": "Turn your phone into a wireless mouse, keyboard and volume remote for any Windows PC over Wi-Fi. Install on the PC only; the phone opens a web page (PWA). LAN-only, no account, open-source.",
46+
"softwareVersion": "0.1.1",
47+
"fileSize": "27 MB",
48+
"url": "https://creationsofm7.github.io/localtv-remote/",
49+
"downloadUrl": "https://github.com/creationsofm7/localtv-remote/releases/download/v0.1.1/LocalTVRemote-Setup-0.1.1.exe",
50+
"softwareHelp": "https://github.com/creationsofm7/localtv-remote",
51+
"license": "https://www.apache.org/licenses/LICENSE-2.0",
52+
"author": { "@type": "Person", "name": "Mudit Pandey" },
53+
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" }
54+
}
55+
</script>
56+
<script type="application/ld+json">
57+
{
58+
"@context": "https://schema.org",
59+
"@type": "FAQPage",
60+
"mainEntity": [
61+
{
62+
"@type": "Question",
63+
"name": "How do I control my laptop from my phone without installing an app?",
64+
"acceptedAnswer": { "@type": "Answer", "text": "Install LocalTV Remote on your Windows PC — it's the only device that needs anything installed. Scan the QR code with your phone's camera and your browser opens a trackpad, keyboard and volume remote. Nothing to install on the phone, no app store, no account." }
65+
},
66+
{
67+
"@type": "Question",
68+
"name": "Can multiple people control one PC at the same time?",
69+
"acceptedAnswer": { "@type": "Answer", "text": "Yes. Several phones can connect at once, each paired independently with its own QR code and 6-digit PIN — no single shared remote to hand around." }
70+
},
71+
{
72+
"@type": "Question",
73+
"name": "Is there a free, open-source alternative to Unified Remote or Remote Mouse?",
74+
"acceptedAnswer": { "@type": "Answer", "text": "LocalTV Remote is free, Apache-2.0 open-source, needs no companion app on the phone, and has no paid tier. It runs LAN-only with no cloud relay or account." }
75+
}
76+
]
77+
}
78+
</script>
79+
80+
<style>
81+
:root{
82+
--ink:#111111;
83+
--paper:#ffffff;
84+
--muted:#6b6b6b;
85+
--line:#e6e6e6;
86+
--neon:#ccff00; /* highlighter */
87+
--neon-2:#9bff3d; /* second accent */
88+
--maxw:660px;
89+
}
90+
*{box-sizing:border-box;}
91+
html,body{height:100%;}
92+
body{
93+
margin:0;
94+
background:var(--paper);
95+
color:var(--ink);
96+
font-family:"Courier Prime", ui-monospace, "Cascadia Mono", monospace;
97+
-webkit-font-smoothing:antialiased;
98+
text-rendering:optimizeLegibility;
99+
overflow:hidden; /* no-scroll */
100+
display:grid;
101+
place-items:center;
102+
padding:clamp(18px,4vw,40px);
103+
}
104+
/* faint paper grain — craft, not colour */
105+
body::after{
106+
content:"";position:fixed;inset:0;pointer-events:none;z-index:5;opacity:.035;
107+
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
108+
}
109+
110+
main{
111+
width:100%;
112+
max-width:var(--maxw);
113+
display:flex;
114+
flex-direction:column;
115+
gap:clamp(16px,2.6vh,26px);
116+
}
117+
118+
/* ── letterhead ── */
119+
.head{
120+
display:flex;align-items:baseline;justify-content:space-between;
121+
border-bottom:1.5px solid var(--ink);
122+
padding-bottom:10px;
123+
font-size:12px;letter-spacing:.22em;text-transform:uppercase;
124+
}
125+
.head b{font-weight:700;}
126+
.head span{color:var(--muted);letter-spacing:.18em;}
127+
128+
/* ── headline ── */
129+
h1{
130+
font-family:"Fraunces", Georgia, serif;
131+
font-weight:500;
132+
font-size:clamp(2.1rem,6.2vw,3.5rem);
133+
line-height:1.04;
134+
letter-spacing:-0.015em;
135+
margin:0;
136+
}
137+
138+
/* ── highlighter mark (SVG behind text) ── */
139+
.mark{position:relative;white-space:nowrap;}
140+
.mark > svg{
141+
position:absolute;left:-4px;right:-4px;bottom:.02em;
142+
width:calc(100% + 8px);height:.78em;z-index:-1;
143+
mix-blend-mode:multiply;
144+
transform:scaleX(0) rotate(-.5deg);transform-origin:left center;
145+
animation:swipe .7s cubic-bezier(.6,.02,.2,1) forwards;
146+
}
147+
.mark.m2 > svg{animation-delay:1.0s;}
148+
@keyframes swipe{to{transform:scaleX(1) rotate(-.5deg);}}
149+
150+
/* ── the typed letter ── */
151+
.letter{font-size:clamp(.92rem,1.05rem + .2vw,1.06rem);line-height:1.72;}
152+
.letter p{margin:0 0 .82em;}
153+
.letter .salute{color:var(--muted);}
154+
.sign{margin-top:.4em;}
155+
.sign .name{border-bottom:2px solid var(--neon-2);padding-bottom:1px;}
156+
/* typewriter caret */
157+
.caret::after{
158+
content:"";display:inline-block;width:.6ch;height:1.05em;
159+
background:var(--ink);margin-left:2px;transform:translateY(.16em);
160+
animation:blink 1s steps(1) infinite;
161+
}
162+
@keyframes blink{50%{opacity:0;}}
163+
164+
/* ── call to action ── */
165+
.cta-row{display:flex;flex-wrap:wrap;align-items:center;gap:14px 18px;}
166+
.cta{
167+
--b:#111;
168+
font-family:"Courier Prime",monospace;font-weight:700;font-size:1rem;
169+
letter-spacing:.02em;text-decoration:none;color:#fff;background:var(--b);
170+
padding:14px 22px;border:1.5px solid var(--ink);
171+
box-shadow:5px 5px 0 var(--neon);
172+
transition:transform .12s ease, box-shadow .12s ease, background .12s ease;
173+
}
174+
.cta:hover{transform:translate(2px,2px);box-shadow:2px 2px 0 var(--neon);background:#000;}
175+
.cta:active{transform:translate(5px,5px);box-shadow:0 0 0 var(--neon);}
176+
.meta{font-size:12.5px;color:var(--muted);letter-spacing:.02em;}
177+
.meta b{color:var(--ink);font-weight:700;}
178+
179+
.links{font-size:13px;display:flex;gap:18px;flex-wrap:wrap;}
180+
.links a{color:var(--ink);text-decoration:none;border-bottom:1.5px solid var(--line);padding-bottom:2px;transition:border-color .15s;}
181+
.links a:hover{border-color:var(--ink);}
182+
.links .soon{color:var(--muted);border:none;}
183+
184+
/* ── quiet FAQ (keeps FAQPage data legitimate) ── */
185+
.faq{border-top:1px solid var(--line);padding-top:12px;display:flex;flex-direction:column;}
186+
.faq details{border-bottom:1px solid var(--line);}
187+
.faq summary{
188+
list-style:none;cursor:pointer;padding:9px 0;font-size:12.5px;
189+
letter-spacing:.04em;display:flex;justify-content:space-between;gap:12px;
190+
}
191+
.faq summary::-webkit-details-marker{display:none;}
192+
.faq summary::after{content:"+";color:var(--muted);}
193+
.faq details[open] summary::after{content:"–";}
194+
.faq p{margin:0 0 12px;font-size:13px;line-height:1.6;color:#333;}
195+
196+
/* never clip content on phones / short screens */
197+
@media (max-width:640px), (max-height:680px){
198+
body{overflow:auto;place-items:start center;}
199+
}
200+
201+
@media (prefers-reduced-motion:reduce){
202+
.mark > svg{animation:none;transform:scaleX(1) rotate(-.5deg);}
203+
.caret::after{animation:none;}
204+
}
205+
</style>
206+
</head>
207+
208+
<body>
209+
<main>
210+
<header class="head">
211+
<b>LocalTV&nbsp;Remote</b>
212+
<span>Windows&nbsp;· free&nbsp;· open&nbsp;source</span>
213+
</header>
214+
215+
<h1>Control your Windows&nbsp;PC <span class="mark">from your phone.<svg viewBox="0 0 320 44" preserveAspectRatio="none" aria-hidden="true"><path d="M5,26 C70,15 150,12 210,14 C265,16 300,17 315,21 C319,30 312,38 292,39 C200,44 95,42 36,38 C12,36 1,33 5,26 Z" fill="#ccff00"/></svg></span></h1>
216+
217+
<section class="letter" aria-label="A note from the maker">
218+
<p class="salute">Dear whoever keeps getting up to hit&nbsp;pause,</p>
219+
<p>I made LocalTV Remote so your phone is the mouse, keyboard, and volume for your PC. Over Wi-Fi. On your network, nobody&nbsp;else's.</p>
220+
<p>You install it once — on the PC. Your phone just opens a web page: no app store, no account, no cloud. Scan a QR and you're in. Pass the link to a friend and they get their own remote too, their own&nbsp;PIN.</p>
221+
<p>Free. Open source. About 27&nbsp;MB. That's the whole&nbsp;pitch.</p>
222+
<p class="sign">— Mudit, <span class="name">maker of LocalTV</span></p>
223+
</section>
224+
225+
<div>
226+
<div class="cta-row">
227+
<a class="cta" href="https://github.com/creationsofm7/localtv-remote/releases/download/v0.1.1/LocalTVRemote-Setup-0.1.1.exe">Download for Windows — Free</a>
228+
<span class="meta"><b>v0.1.1</b> · ~27&nbsp;MB · Windows&nbsp;10&nbsp;/&nbsp;11 · no account, no&nbsp;cloud</span>
229+
</div>
230+
</div>
231+
232+
<nav class="links">
233+
<a href="https://github.com/creationsofm7/localtv-remote">Read the source on GitHub</a>
234+
<a href="https://github.com/creationsofm7/localtv-remote/releases/latest">All releases</a>
235+
<span class="soon">winget — coming soon</span>
236+
</nav>
237+
238+
<section class="faq" aria-label="Frequently asked questions">
239+
<details>
240+
<summary>Do I need to install an app on my phone?</summary>
241+
<p>No. You only install LocalTV Remote on the Windows PC. Your phone scans a QR code and opens a controller page in the browser — a trackpad, keyboard and volume remote. No app store, no account.</p>
242+
</details>
243+
<details>
244+
<summary>Can several people control one PC at once?</summary>
245+
<p>Yes. Multiple phones connect at the same time, each paired independently with its own QR code and 6-digit PIN — no single shared remote to pass around.</p>
246+
</details>
247+
<details>
248+
<summary>Is it a free alternative to Unified Remote / Remote Mouse?</summary>
249+
<p>It is — free, Apache-2.0 open-source, no companion app on the phone, no paid tier, and LAN-only with no cloud relay or account.</p>
250+
</details>
251+
</section>
252+
</main>
253+
254+
<script>
255+
// Typewriter — types the letter while keeping the real text in the DOM for SEO.
256+
(function () {
257+
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
258+
var letter = document.querySelector('.letter');
259+
if (!letter || reduce) return;
260+
261+
var blocks = Array.prototype.slice.call(letter.querySelectorAll('p'));
262+
var saved = blocks.map(function (b) { return b.textContent; });
263+
blocks.forEach(function (b) { b.textContent = ''; b.style.minHeight = '1.2em'; });
264+
265+
var bi = 0;
266+
function typeBlock() {
267+
if (bi >= blocks.length) return;
268+
var el = blocks[bi], text = saved[bi], ci = 0;
269+
el.classList.add('caret');
270+
(function tick() {
271+
if (ci <= text.length) {
272+
el.textContent = text.slice(0, ci);
273+
ci++;
274+
// slight human jitter; pause a touch on punctuation
275+
var ch = text.charAt(ci - 2);
276+
var d = 18 + Math.random() * 26 + (/[,.]/.test(ch) ? 140 : 0);
277+
setTimeout(tick, d);
278+
} else {
279+
el.classList.remove('caret');
280+
bi++;
281+
setTimeout(typeBlock, 230);
282+
}
283+
})();
284+
}
285+
typeBlock();
286+
})();
287+
</script>
288+
</body>
289+
</html>

0 commit comments

Comments
 (0)