diff --git a/README.md b/README.md index b1f0319..85eb0db 100644 --- a/README.md +++ b/README.md @@ -60,11 +60,14 @@ the MIT license, and needs no account. | | Requirements | Get it | | --- | --- | --- | | **Windows** | Windows 10 (version 1809 or later) or Windows 11, 64-bit, with an NVIDIA, AMD or Intel GPU | [EternalMonitor-Setup.exe](https://github.com/sidebandstudio/EternalMonitor/releases/tag/v0.3.0) (v0.3.0 current stable) | -| **iPad** | iPadOS 17 or later | [TestFlight v0.3.0, build 143](https://testflight.apple.com/join/ppc9QfXc). External installation opens after Apple approves the build. | +| **iPad** | iPadOS 17 or later | [TestFlight v0.3.0, build 143](https://testflight.apple.com/join/ppc9QfXc). The public beta is open: install TestFlight, then open the link on your iPad. | Install both apps from the same version. The older v0.1 releases use a different protocol and cannot connect to the v0.3 iPad app. +Testing it? Send bugs and feedback through the [form on the download page](https://eternalmonitor.dev/download.html#feedback), +which emails hello@sideband.studio, or open a [GitHub issue](https://github.com/sidebandstudio/EternalMonitor/issues/new/choose). + The installer is not code-signed yet, so Windows SmartScreen asks before it runs. Choose **More info**, then **Run anyway**, only after checking that the file's SHA-256 matches the one on the [release page](https://github.com/sidebandstudio/EternalMonitor/releases). diff --git a/SETUP.md b/SETUP.md index da31e22..99a82f9 100644 --- a/SETUP.md +++ b/SETUP.md @@ -51,12 +51,12 @@ the Start menu. To have it open whenever you sign in to Windows, go to ## Step 2: Install EternalMonitor on your iPad The iPad app installs through Apple's TestFlight app. Use v0.3.0, build 143, -with the current stable Windows release. External installation requires -Apple's beta review approval. +with the current stable Windows release. The beta is open to anyone with the +invite link. 1. On the iPad, install **TestFlight** from the App Store. 2. Open the [EternalMonitor TestFlight invite](https://testflight.apple.com/join/ppc9QfXc), - then tap **Accept** and **Install** once the build is available. + then tap **Accept** and **Install**. 3. Open **EternalMonitor** on the iPad. ## Step 3: Connect over Wi-Fi diff --git a/docs/beta-testing.md b/docs/beta-testing.md index 06a5747..fe2801c 100644 --- a/docs/beta-testing.md +++ b/docs/beta-testing.md @@ -23,11 +23,12 @@ https://testflight.apple.com/join/ppc9QfXc The App Store Connect app and CI signing credentials are already configured for `sidebandstudio/EternalMonitor`. iPad v0.3.0, build 143, was uploaded and -submitted for external beta review on September 25, 2026. It belongs to the +submitted for external beta review on September 25, 2026, and Apple approved it +on September 26, 2026. It belongs to the `FriendsExternal` group, whose public link and automatic tester notification are enabled. The feedback and review contact email is `Whois.younes@gmail.com`. -External installation opens after Apple approves the build. Pair it with the +External installation is open. Pair it with the [current stable Windows release](https://github.com/sidebandstudio/EternalMonitor/releases/tag/v0.3.0). The setup instructions below are for maintaining or replacing that configuration. @@ -139,8 +140,13 @@ Two links, and they must match: - The v0.3.0 Windows installer, shown as the current stable release on eternalmonitor.dev/download.html. Its bytes are unchanged from v0.3.0-rc.1. -- The TestFlight public link for iPad v0.3.0, build 143. External installation - requires Apple's beta review approval. +- The TestFlight public link for iPad v0.3.0, build 143. Apple approved it for + external testing on September 26, 2026. + +Tell them where feedback goes: the form at +https://eternalmonitor.dev/download.html#feedback (it opens their mail app +addressed to hello@sideband.studio), TestFlight's Send Beta Feedback, or a +GitHub issue. Use the matching release pair. v0.1 and v2 builds cannot stream together. v0.3 keeps the v2 prefix and negotiates new features, but mixing older builds diff --git a/docs/download.html b/docs/download.html index d0601f9..24be1a7 100644 --- a/docs/download.html +++ b/docs/download.html @@ -48,8 +48,8 @@

Download EternalMonitor

-

v0.3.0 is the current stable release. Install it on Windows with iPad v0.3.0, TestFlight build 143.

-

New to EternalMonitor? The setup guide walks through every step, including USB with Apple Devices.

+

v0.3.0 is the current stable release. Install it on Windows with iPad v0.3.0, TestFlight build 143. The iPad beta is open to everyone through TestFlight.

+

New to EternalMonitor? The setup guide walks through every step, including USB with Apple Devices. Found a bug? Tell us below.

@@ -75,7 +75,7 @@

Windows

SHA-256 70bd59be737423d636a53b27d7e0fbe9b9e8563ecc104d79f153b139be904a12 -

Release notes and known issues

+

Release notes and known issues · Report a problem

@@ -83,21 +83,101 @@

Windows

iPad

- TestFlight + TestFlight beta

v0.3.0, build 143. Shows your PC's screen and sends touch, Apple Pencil pressure and tilt, and keyboard input back. Use Drawing mode for Pencil input with palm rejection.

-

Build 143 is awaiting Apple's beta review. External installation opens after approval.

- Open TestFlight invite +

Build 143 passed Apple's beta review. Anyone with the link can install it now.

+ Join the TestFlight beta
+
    +
  1. Install TestFlight from the App Store on your iPad.
  2. +
  3. Open the invite on the iPad, then tap Accept and Install.
  4. +
  5. Open EternalMonitor and pair it with your PC.
  6. +
+ + + Testing the beta? Send bugs and feedback with the form below, or email hello@sideband.studio. +

Developers can also build it from source.

+
+
+ +
+
+
@@ -134,7 +214,7 @@

iPad app

diff --git a/docs/index.html b/docs/index.html index 90150c0..8fff2c1 100644 --- a/docs/index.html +++ b/docs/index.html @@ -220,7 +220,7 @@

v0.3.0

Current stable

-

Version 0.3.0 includes USB, PC audio, pairing, keyboard control, Apple Pencil drawing and packet repair. Install the Windows release with iPad v0.3.0, TestFlight build 143. Get both on the download page, including the current TestFlight availability.

+

Version 0.3.0 includes USB, PC audio, pairing, keyboard control, Apple Pencil drawing and packet repair. Install the Windows release with iPad v0.3.0, TestFlight build 143. The iPad beta is open to everyone, and both are on the download page, along with a form for bug reports and feedback.

See the release notes for setup details and known issues.

@@ -279,7 +279,11 @@

Questions

Where do I get the iPad app? -

The iPad app is distributed through TestFlight. The download page has the public invite and availability for v0.3.0, build 143. Install it with the v0.3.0 Windows release. Developers can also build it from source.

+

The iPad app is distributed through TestFlight, and the v0.3.0 beta (build 143) is open to everyone. Install the TestFlight app on your iPad, then open the public invite from the download page. Install it with the v0.3.0 Windows release. Developers can also build it from source.

+
+
+ Found a bug, or have feedback? +

Use the feedback form on the download page. It sends your report to hello@sideband.studio with the version details filled in. Bug reports are also welcome as GitHub issues.

@@ -311,7 +315,7 @@

Put your iPad to work

diff --git a/docs/script.js b/docs/script.js index bf2ee82..f21df74 100644 --- a/docs/script.js +++ b/docs/script.js @@ -121,6 +121,86 @@ }); }); + /* --- Feedback form: opens the visitor's mail app with the report filled in --- */ + var feedbackForm = document.getElementById('feedback-form'); + if (feedbackForm) { + var FEEDBACK_TO = 'hello@sideband.studio'; + var stepsField = document.getElementById('fb-steps-field'); + var fallback = document.getElementById('feedback-fallback'); + var preview = document.getElementById('feedback-preview'); + var copyBtn = document.getElementById('feedback-copy'); + var copied = document.getElementById('feedback-copied'); + + var feedbackKind = function () { + var checked = feedbackForm.querySelector('input[name="kind"]:checked'); + return checked ? checked.value : 'Bug'; + }; + var fieldValue = function (id) { + var el = document.getElementById(id); + return el ? el.value.trim() : ''; + }; + + // Steps only make sense for a bug. + var syncKind = function () { + if (stepsField) stepsField.hidden = feedbackKind() !== 'Bug'; + }; + Array.prototype.forEach.call(feedbackForm.querySelectorAll('input[name="kind"]'), function (radio) { + radio.addEventListener('change', syncKind); + }); + syncKind(); + + var composeBody = function () { + var lines = [fieldValue('fb-message'), '']; + if (feedbackKind() === 'Bug' && fieldValue('fb-steps')) { + lines.push('Steps to reproduce:', fieldValue('fb-steps'), ''); + } + lines.push( + 'iPad: ' + (fieldValue('fb-ipad') || 'not given'), + 'PC: ' + (fieldValue('fb-pc') || 'not given'), + 'Connection: ' + (fieldValue('fb-connection') || 'not sure'), + 'Release: ' + (feedbackForm.getAttribute('data-release') || ''), + 'Sent from eternalmonitor.dev/download.html' + ); + return lines.join('\n'); + }; + + feedbackForm.addEventListener('submit', function (e) { + e.preventDefault(); + if (!feedbackForm.reportValidity()) return; + var kind = feedbackKind() === 'Bug' ? 'bug' : 'feedback'; + var firstLine = fieldValue('fb-message').split('\n')[0].slice(0, 70); + var subject = '[EternalMonitor ' + kind + '] ' + firstLine; + var body = composeBody(); + if (preview) preview.textContent = 'To: ' + FEEDBACK_TO + '\nSubject: ' + subject + '\n\n' + body; + if (fallback) fallback.hidden = false; + window.location.href = 'mailto:' + FEEDBACK_TO + + '?subject=' + encodeURIComponent(subject) + + '&body=' + encodeURIComponent(body); + }); + + if (copyBtn) { + copyBtn.addEventListener('click', function () { + var text = preview ? preview.textContent : ''; + var done = function () { + if (!copied) return; + copied.hidden = false; + setTimeout(function () { copied.hidden = true; }, 2000); + }; + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(text).then(done, function () {}); + } else if (preview) { + var range = document.createRange(); + range.selectNodeContents(preview); + var selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + try { if (document.execCommand('copy')) done(); } catch (err) {} + selection.removeAllRanges(); + } + }); + } + } + /* --- GitHub Releases API Fetch --- */ var downloadBtn = document.getElementById('download-btn'); var versionEl = document.getElementById('release-version'); diff --git a/docs/style.css b/docs/style.css index 1f4174f..b007af5 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1555,6 +1555,291 @@ code { line-height: 1.7; } +/* --- TestFlight open, install steps and feedback --------------------------- */ + +.testflight-status--open { + display: flex; + align-items: flex-start; + gap: 12px; + border-style: solid; + border-color: rgba(var(--accent-rgb), 0.28); + background: rgba(var(--accent-rgb), 0.06); + color: var(--text); +} + +.testflight-status--open .eyebrow-dot { + flex-shrink: 0; + margin-top: 8px; +} + +.install-steps { + display: grid; + gap: 8px; + padding-left: 22px; + color: var(--muted); + font-size: 0.925rem; +} + +.install-steps strong { + color: var(--text); + font-weight: 500; +} + +.feedback-callout { + display: flex; + align-items: flex-start; + gap: 12px; + padding: 14px 16px; + border-radius: 12px; + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-strong); + color: var(--muted); + font-size: 0.925rem; + transition: border-color 0.2s var(--ease), background 0.2s var(--ease); +} + +.feedback-callout:hover { + border-color: rgba(var(--accent-rgb), 0.4); + background: rgba(var(--accent-rgb), 0.05); +} + +.feedback-callout svg { + flex-shrink: 0; + width: 18px; + height: 18px; + margin-top: 2px; + color: var(--accent); +} + +.feedback-callout strong { + color: var(--text); + font-weight: 500; +} + +.feedback-section { + padding: 16px 0 0; +} + +.feedback-card { + display: grid; + grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); + gap: 40px; + padding: 40px; +} + +.feedback-kicker { + display: block; + color: var(--accent); + font-family: var(--font-mono); + font-size: 0.8rem; + letter-spacing: 0.12em; + text-transform: uppercase; +} + +.feedback-intro h2 { + margin-top: 14px; + font-size: clamp(1.5rem, 2.6vw, 2rem); +} + +.feedback-intro p { + margin-top: 14px; + color: var(--muted); +} + +.feedback-intro p strong { + color: var(--text); + font-weight: 500; +} + +.feedback-intro a, +.feedback-fallback a { + color: var(--accent); +} + +.feedback-form { + display: grid; + gap: 18px; + align-content: start; +} + +.field { + display: grid; + gap: 8px; +} + +.field[hidden] { + display: none; +} + +.field--choice { + border: 0; + min-width: 0; +} + +.field label, +.field legend { + font-size: 0.9rem; + font-weight: 500; +} + +.field legend { + padding: 0; + margin-bottom: 8px; +} + +.field .optional { + margin-left: 6px; + color: var(--faint); + font-weight: 400; +} + +.field input, +.field textarea, +.field select { + width: 100%; + padding: 12px 14px; + border-radius: 12px; + background: var(--bg); + border: 1px solid var(--border-strong); + color: var(--text); + font: inherit; + font-size: 0.95rem; + line-height: 1.5; + transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease); +} + +.field textarea { + min-height: 96px; + resize: vertical; +} + +.field select { + appearance: none; + -webkit-appearance: none; + padding-right: 40px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23a1a1aa' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 8l4 4 4-4'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 14px center; + background-size: 16px; +} + +.field input::placeholder, +.field textarea::placeholder { + color: var(--faint); +} + +.field input:focus-visible, +.field textarea:focus-visible, +.field select:focus-visible { + outline: none; + border-color: rgba(var(--accent-rgb), 0.6); + box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.16); +} + +.choice-group { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.choice { + position: relative; +} + +.choice input { + position: absolute; + width: 1px; + height: 1px; + opacity: 0; +} + +.choice span { + display: inline-flex; + align-items: center; + height: 40px; + padding: 0 16px; + border-radius: 999px; + border: 1px solid var(--border-strong); + background: rgba(255, 255, 255, 0.04); + color: var(--muted); + font-size: 0.925rem; + font-weight: 500; + cursor: pointer; + transition: background 0.15s var(--ease), border-color 0.15s var(--ease), + color 0.15s var(--ease); +} + +.choice input:checked + span { + background: rgba(var(--accent-rgb), 0.12); + border-color: rgba(var(--accent-rgb), 0.4); + color: var(--accent); +} + +.choice input:focus-visible + span { + outline: 2px solid rgba(var(--accent-rgb), 0.8); + outline-offset: 3px; +} + +.field-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 14px; +} + +.field-row .field:last-child { + grid-column: 1 / -1; +} + +.feedback-actions { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 14px; + margin-top: 4px; +} + +.feedback-fallback { + grid-column: 1 / -1; + display: grid; + gap: 12px; + padding: 18px 20px; + border-radius: 12px; + background: var(--bg); + border: 1px solid rgba(var(--accent-rgb), 0.28); + color: var(--muted); + font-size: 0.925rem; +} + +.feedback-fallback[hidden] { + display: none; +} + +.feedback-fallback strong { + color: var(--text); +} + +.feedback-fallback pre { + overflow-x: auto; + padding: 14px 16px; + border-radius: 10px; + background: var(--surface); + border: 1px solid var(--border); + white-space: pre-wrap; + word-break: break-word; +} + +.feedback-fallback pre code { + color: var(--text); + font-size: 0.82rem; + line-height: 1.6; +} + +.feedback-fallback-actions { + display: flex; + align-items: center; + gap: 12px; +} + /* --- Motion ---------------------------------------------------------------- */ /* script.js swaps the html class from no-js to js and adds .visible when a .reveal element scrolls into view. Without JavaScript nothing is hidden. */ @@ -1724,6 +2009,11 @@ code { .download-grid { grid-template-columns: 1fr; } + + .feedback-card { + grid-template-columns: 1fr; + gap: 28px; + } } @media (max-width: 720px) { @@ -1777,6 +2067,14 @@ code { padding: 24px 20px; } + .feedback-card { + padding: 28px 22px; + } + + .field-row { + grid-template-columns: 1fr; + } + .build-details { padding: 0 20px; } @@ -1792,7 +2090,8 @@ code { padding: 0 18px; } - .hero-actions .btn { + .hero-actions .btn, + .feedback-actions .btn { width: 100%; } diff --git a/scripts/QUICKSTART.txt b/scripts/QUICKSTART.txt index c864b13..709e9e8 100644 --- a/scripts/QUICKSTART.txt +++ b/scripts/QUICKSTART.txt @@ -26,8 +26,9 @@ and its tasks, plus TCP/UDP firewall rules. Start EternalMonitor. Install Apple's TestFlight app, then open the EternalMonitor invite: https://testflight.apple.com/join/ppc9QfXc -Install v0.3.0, build 143. External installation opens after Apple approves -the build; the download page above shows its availability. +Install v0.3.0, build 143. The beta is open to anyone with the link. +Send bugs and feedback through the form on the download page above, which +emails hello@sideband.studio. 2. Connect and pair over WiFi ----------------------------