From 5cba830813de413dbe62ed8eee99344d5928c8bb Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Fri, 3 Jul 2026 10:59:04 +0000 Subject: [PATCH] Harden live auth and public release surfaces --- UnrealHyperTwist/Config/DefaultEngine.ini | 3 +- scripts/Invoke-HyperTwistDesktopPackage.ps1 | 88 ++ scripts/Launch-HyperTwistDesktopPackage.ps1 | 130 +++ website/index.html | 10 +- website/server/package.json | 3 +- .../server/scripts/set-manual-entitlement.ts | 106 +++ .../__tests__/auth-session-payload.test.ts | 70 ++ website/server/src/auth-session-payload.ts | 79 ++ website/server/src/billing-state.ts | 74 +- website/server/src/index.ts | 17 +- website/src/__tests__/App.bootstrap.test.tsx | 2 +- .../__tests__/DashboardOverviewPage.test.tsx | 6 +- website/src/__tests__/app-route-tree.test.tsx | 38 +- .../__tests__/download-center-page.test.tsx | 2 +- .../__tests__/protected-app-pages.test.tsx | 12 +- .../src/__tests__/public-auth-pages.test.tsx | 26 +- .../__tests__/public-marketing-pages.test.tsx | 254 +++--- website/src/__tests__/route-shells.test.tsx | 6 +- website/src/auth/auth-shell-backdrop.ts | 2 +- .../src/components/layout/MarketingShell.tsx | 81 +- .../src/components/routes/ProtectedRoute.tsx | 6 +- website/src/components/seo/SiteMetadata.tsx | 2 +- .../components/ui/BrowserAuthMethodsGuide.tsx | 41 +- .../src/components/ui/HyperTwistButton.tsx | 1 - website/src/pages/auth-pages.tsx | 72 +- website/src/pages/public-page-helpers.tsx | 212 ++--- website/src/pages/public-pages-commerce.tsx | 140 ++-- website/src/pages/public-pages-features.tsx | 52 +- website/src/pages/public-pages-guides.tsx | 115 +-- website/src/pages/public-pages-launch.tsx | 20 +- website/src/pages/public-pages-marketing.tsx | 305 +++---- website/src/public-route-registry.json | 66 +- website/src/router/AppRouteTree.tsx | 24 +- website/src/site-config.ts | 50 +- website/src/site-data.ts | 782 +++++++++--------- website/src/styles/global.css | 453 +++++++++- .../tests/e2e/responsive-public-pages.spec.ts | 18 +- 37 files changed, 2167 insertions(+), 1201 deletions(-) create mode 100644 scripts/Invoke-HyperTwistDesktopPackage.ps1 create mode 100644 scripts/Launch-HyperTwistDesktopPackage.ps1 create mode 100644 website/server/scripts/set-manual-entitlement.ts create mode 100644 website/server/src/__tests__/auth-session-payload.test.ts create mode 100644 website/server/src/auth-session-payload.ts diff --git a/UnrealHyperTwist/Config/DefaultEngine.ini b/UnrealHyperTwist/Config/DefaultEngine.ini index 81bfce6..b1bfa37 100644 --- a/UnrealHyperTwist/Config/DefaultEngine.ini +++ b/UnrealHyperTwist/Config/DefaultEngine.ini @@ -1,7 +1,8 @@ [/Script/EngineSettings.GameMapsSettings] -GameDefaultMap=/Engine/Maps/Templates/OpenWorld +GameDefaultMap=/Engine/Maps/Entry +ServerDefaultMap=/Engine/Maps/Entry GlobalDefaultGameMode=/Script/UnrealHyperTwist.HyperTwistFirstRunLaunchGameMode [/Script/Engine.RendererSettings] diff --git a/scripts/Invoke-HyperTwistDesktopPackage.ps1 b/scripts/Invoke-HyperTwistDesktopPackage.ps1 new file mode 100644 index 0000000..d443027 --- /dev/null +++ b/scripts/Invoke-HyperTwistDesktopPackage.ps1 @@ -0,0 +1,88 @@ +param( + [string]$ProjectRoot = 'C:\HyperTwist', + [string]$ArchiveDirectory = 'C:\HyperTwist\packaged\desktop', + [ValidateSet('Development', 'Shipping')] + [string]$Configuration = 'Development', + [string]$CookMap = '/Game/HyperTwistTraining/Maps/L_HyperTwist_ClassicTraining', + [string[]]$AdditionalCookMaps = @( + '/Game/HyperTwistTraining/Maps/L_HyperTwist_FollowAlongTraining', + '/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining', + '/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining' + ), + [string[]]$SmokeMaps = @( + '/Game/HyperTwistTraining/Maps/L_HyperTwist_ClassicTraining', + '/Game/HyperTwistTraining/Maps/L_HyperTwist_FollowAlongTraining', + '/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining', + '/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining' + ), + [string[]]$AdditionalCookerOptions = @( + '-DisablePlugins=MovieRenderPipeline', + '-SkipCookingEditorContent' + ), + [string]$ValidationReportPath = '', + [string]$LaunchSurfaceReportPath = '', + [switch]$CleanArchive, + [switch]$SkipBuild, + [switch]$SkipLaunch +) + +$ErrorActionPreference = 'Stop' + +$ClassicPackageScriptPath = Join-Path $PSScriptRoot 'Invoke-HyperTwistClassicCubePackage.ps1' +$DesktopLaunchScriptPath = Join-Path $PSScriptRoot 'Launch-HyperTwistDesktopPackage.ps1' +$ValidationDirectory = Join-Path $ArchiveDirectory 'validation' + +if (-not (Test-Path -LiteralPath $ClassicPackageScriptPath)) +{ + throw "Classic-cube package helper was not found at '$ClassicPackageScriptPath'." +} + +if (-not (Test-Path -LiteralPath $DesktopLaunchScriptPath)) +{ + throw "Desktop launch helper was not found at '$DesktopLaunchScriptPath'." +} + +if ([string]::IsNullOrWhiteSpace($ValidationReportPath)) +{ + $ValidationReportPath = Join-Path $ValidationDirectory 'desktop-package-validation-report.json' +} + +if ([string]::IsNullOrWhiteSpace($LaunchSurfaceReportPath)) +{ + $LaunchSurfaceReportPath = Join-Path $ValidationDirectory 'desktop-launch-surface-report.json' +} + +$InvokeParameters = @{ + ProjectRoot = $ProjectRoot + ArchiveDirectory = $ArchiveDirectory + Configuration = $Configuration + CookMap = $CookMap + AdditionalCookMaps = $AdditionalCookMaps + SmokeMaps = $SmokeMaps + AdditionalCookerOptions = $AdditionalCookerOptions + ValidationReportPath = $ValidationReportPath +} + +if ($CleanArchive) +{ + $InvokeParameters.CleanArchive = $true +} + +if ($SkipBuild) +{ + $InvokeParameters.SkipBuild = $true +} + +if ($SkipLaunch) +{ + $InvokeParameters.SkipLaunch = $true +} + +& $ClassicPackageScriptPath @InvokeParameters + +if (-not $SkipLaunch) +{ + & $DesktopLaunchScriptPath ` + -PackageRoot $ArchiveDirectory ` + -ReportPath $LaunchSurfaceReportPath +} diff --git a/scripts/Launch-HyperTwistDesktopPackage.ps1 b/scripts/Launch-HyperTwistDesktopPackage.ps1 new file mode 100644 index 0000000..3b413a1 --- /dev/null +++ b/scripts/Launch-HyperTwistDesktopPackage.ps1 @@ -0,0 +1,130 @@ +param( + [string]$PackageRoot = 'C:\HyperTwist\packaged\desktop', + [string]$MapUrl = '', + [int]$SmokeSeconds = 12, + [int]$ResX = 1600, + [int]$ResY = 900, + [string]$ReportPath = '', + [switch]$KeepRunning +) + +$ErrorActionPreference = 'Stop' + +function Write-Utf8JsonFile { + param( + [Parameter(Mandatory = $true)] + [string]$Path, + [Parameter(Mandatory = $true)] + [object]$Value + ) + + $ParentPath = Split-Path -Parent $Path + if (-not [string]::IsNullOrWhiteSpace($ParentPath)) + { + New-Item -ItemType Directory -Force -Path $ParentPath | Out-Null + } + + $Json = $Value | ConvertTo-Json -Depth 8 + $Utf8NoBom = New-Object System.Text.UTF8Encoding($false) + [System.IO.File]::WriteAllText($Path, $Json, $Utf8NoBom) +} + +$CandidateExecutablePaths = @( + (Join-Path $PackageRoot 'Windows\UnrealHyperTwist.exe'), + (Join-Path $PackageRoot 'WindowsNoEditor\UnrealHyperTwist.exe'), + (Join-Path $PackageRoot 'UnrealHyperTwist.exe') +) + +$ExecutablePath = $CandidateExecutablePaths | Where-Object { Test-Path $_ } | Select-Object -First 1 +if ($null -eq $ExecutablePath) +{ + throw "No packaged UnrealHyperTwist executable was found beneath '$PackageRoot'." +} + +$ArgumentList = @( + "-ResX=$ResX", + "-ResY=$ResY", + '-windowed', + '-log' +) + +if (-not [string]::IsNullOrWhiteSpace($MapUrl)) +{ + $ArgumentList = @($MapUrl) + $ArgumentList +} + +Write-Host "Launching packaged HyperTwist desktop experience from '$ExecutablePath'..." +$ResolvedPackageRoot = (Resolve-Path -LiteralPath $PackageRoot).Path +$GeneratedAtUtc = [DateTime]::UtcNow.ToString('o') +$Process = $null +$Report = [ordered]@{ + reportVersion = 'ht-desktop-package-launch-surface/v1' + generatedAtUtc = $GeneratedAtUtc + packageRoot = $ResolvedPackageRoot + executablePath = $ExecutablePath + mapUrl = $MapUrl + smokeSeconds = $SmokeSeconds + resolution = [ordered]@{ + width = $ResX + height = $ResY + } + keepRunning = [bool]$KeepRunning + result = 'failed' + processId = $null + processStopped = $false + exitCode = $null + error = $null +} + +try +{ + $Process = Start-Process -FilePath $ExecutablePath -ArgumentList $ArgumentList -PassThru + Start-Sleep -Seconds $SmokeSeconds + + $Process.Refresh() + $Report.processId = $Process.Id + if ($Process.HasExited) + { + $Report.exitCode = $Process.ExitCode + throw "Packaged desktop executable exited early with code $($Process.ExitCode)." + } + + $Report.result = 'passed' +} +catch +{ + $Report.error = $_.Exception.Message + if ($null -ne $Process) + { + $Process.Refresh() + if ($Process.HasExited) + { + $Report.exitCode = $Process.ExitCode + } + elseif (-not $KeepRunning) + { + Stop-Process -Id $Process.Id -Force + $Report.processStopped = $true + } + } + + if (-not [string]::IsNullOrWhiteSpace($ReportPath)) + { + Write-Utf8JsonFile -Path $ReportPath -Value $Report + } + + throw +} + +Write-Host "Packaged desktop smoke launch succeeded (PID $($Process.Id))." +if (-not $KeepRunning) +{ + Stop-Process -Id $Process.Id -Force + $Report.processStopped = $true + Write-Host 'Stopped packaged desktop smoke process after successful launch validation.' +} + +if (-not [string]::IsNullOrWhiteSpace($ReportPath)) +{ + Write-Utf8JsonFile -Path $ReportPath -Value $Report +} diff --git a/website/index.html b/website/index.html index 634887a..acc9bc7 100644 --- a/website/index.html +++ b/website/index.html @@ -5,14 +5,14 @@ @@ -20,7 +20,7 @@ @@ -134,7 +134,7 @@

Loading HyperTwist...

- Preparing the public product story, shared auth posture, and desktop-first release lane. + Preparing your account access, downloads, release notes, and desktop training workspace.

@@ -169,7 +169,7 @@ backdrop.style.inset = '0'; backdrop.style.zIndex = '0'; backdrop.style.pointerEvents = 'none'; - backdrop.style.background = 'radial-gradient(circle at top, rgba(216,203,175,0.12), transparent 40%), linear-gradient(180deg, rgba(18,20,24,0.97), rgba(10,12,17,0.99))'; + backdrop.style.background = 'radial-gradient(circle at top, rgba(84,203,255,0.14), transparent 34%), radial-gradient(circle at 82% 14%, rgba(247,178,103,0.16), transparent 24%), linear-gradient(180deg, rgba(9,12,24,0.86), rgba(7,10,19,0.94))'; document.body.appendChild(backdrop); } } diff --git a/website/server/package.json b/website/server/package.json index 97a46f3..fa43338 100644 --- a/website/server/package.json +++ b/website/server/package.json @@ -8,7 +8,8 @@ "dev": "tsx watch src/index.ts", "start": "tsx src/index.ts", "type-check": "tsc --noEmit", - "test": "vitest run" + "test": "vitest run", + "entitlement:set-manual": "tsx scripts/set-manual-entitlement.ts" }, "dependencies": { "cookie-parser": "^1.4.7", diff --git a/website/server/scripts/set-manual-entitlement.ts b/website/server/scripts/set-manual-entitlement.ts new file mode 100644 index 0000000..8de7135 --- /dev/null +++ b/website/server/scripts/set-manual-entitlement.ts @@ -0,0 +1,106 @@ +import path from 'node:path' +import { + createBillingStateStore, + type BillingPlan, + type BillingRole, +} from '../src/billing-state' + +type ParsedArgs = { + email: string + plan: BillingPlan + role: BillingRole + canDownload: boolean + accessStatus: string +} + +function readArgValue(args: string[], flag: string) { + const index = args.indexOf(flag) + if (index === -1) { + return '' + } + + return String(args[index + 1] || '').trim() +} + +function readBooleanArg(rawValue: string, fallback: boolean) { + const value = rawValue.trim().toLowerCase() + if (!value) { + return fallback + } + if (value === '1' || value === 'true' || value === 'yes' || value === 'on') { + return true + } + if (value === '0' || value === 'false' || value === 'no' || value === 'off') { + return false + } + throw new Error(`Invalid boolean value '${rawValue}'. Use true/false.`) +} + +function normalizePlan(value: string): BillingPlan { + const plan = value.trim().toLowerCase() + if (plan === 'free' || plan === 'operator' || plan === 'studio' || plan === 'enterprise') { + return plan + } + if (plan === 'explorer') { + return 'free' + } + throw new Error(`Unsupported plan '${value}'.`) +} + +function normalizeRole(value: string): BillingRole { + const role = value.trim().toLowerCase() + if (role === 'viewer' || role === 'operator' || role === 'reviewer' || role === 'admin') { + return role + } + throw new Error(`Unsupported role '${value}'.`) +} + +function parseArgs(argv: string[]): ParsedArgs { + const email = readArgValue(argv, '--email').toLowerCase() + if (!email) { + throw new Error('Provide --email user@example.com') + } + + const plan = normalizePlan(readArgValue(argv, '--plan') || 'enterprise') + const role = normalizeRole(readArgValue(argv, '--role') || 'admin') + const canDownload = readBooleanArg(readArgValue(argv, '--can-download'), plan !== 'free') + const accessStatus = readArgValue(argv, '--access-status') || (canDownload ? 'active' : 'manual-review') + + return { + email, + plan, + role, + canDownload, + accessStatus, + } +} + +function resolveBillingStatePath() { + return process.env.BILLING_STATE_PATH + || path.join(process.cwd(), 'data', 'hypertwist-billing-state.json') +} + +function main() { + const parsed = parseArgs(process.argv.slice(2)) + const statePath = resolveBillingStatePath() + const store = createBillingStateStore({ + statePath, + defaultPlan: 'free', + defaultRole: 'operator', + }) + + const entitlement = store.setManualEntitlement({ + email: parsed.email, + plan: parsed.plan, + role: parsed.role, + canDownload: parsed.canDownload, + accessStatus: parsed.accessStatus, + }) + + console.log(JSON.stringify({ + statePath, + entitlement, + }, null, 2)) +} + +main() diff --git a/website/server/src/__tests__/auth-session-payload.test.ts b/website/server/src/__tests__/auth-session-payload.test.ts new file mode 100644 index 0000000..d03632f --- /dev/null +++ b/website/server/src/__tests__/auth-session-payload.test.ts @@ -0,0 +1,70 @@ +import { describe, expect, it, vi } from 'vitest' +import { buildEmailPasswordApiOverrides } from '../auth-session-payload' + +describe('auth-session-payload', () => { + it('stamps email, default plan, and default role onto successful sign-up and sign-in sessions', async () => { + const mergeOnSignUp = vi.fn(async () => {}) + const mergeOnSignIn = vi.fn(async () => {}) + + const overrides = buildEmailPasswordApiOverrides({ + signUpPOST: vi.fn(async (_input: unknown) => ({ + status: 'OK', + user: { + emails: ['Operator@HyperTwist.App'], + }, + session: { + mergeIntoAccessTokenPayload: mergeOnSignUp, + }, + })), + signInPOST: vi.fn(async (_input: unknown) => ({ + status: 'OK', + user: { + emails: ['Operator@HyperTwist.App'], + }, + session: { + mergeIntoAccessTokenPayload: mergeOnSignIn, + }, + })), + }, { + defaultPlan: 'free', + defaultRole: 'operator', + }) + + await overrides.signUpPOST?.({}) + await overrides.signInPOST?.({}) + + expect(mergeOnSignUp).toHaveBeenCalledWith({ + email: 'operator@hypertwist.app', + plan: 'free', + role: 'operator', + }) + expect(mergeOnSignIn).toHaveBeenCalledWith({ + email: 'operator@hypertwist.app', + plan: 'free', + role: 'operator', + }) + }) + + it('does not stamp payload fields when the auth response is not successful', async () => { + const mergeIntoAccessTokenPayload = vi.fn(async () => {}) + + const overrides = buildEmailPasswordApiOverrides({ + signInPOST: vi.fn(async (_input: unknown) => ({ + status: 'WRONG_CREDENTIALS_ERROR', + user: { + emails: ['operator@hypertwist.app'], + }, + session: { + mergeIntoAccessTokenPayload, + }, + })), + }, { + defaultPlan: 'free', + defaultRole: 'operator', + }) + + await overrides.signInPOST?.({}) + + expect(mergeIntoAccessTokenPayload).not.toHaveBeenCalled() + }) +}) diff --git a/website/server/src/auth-session-payload.ts b/website/server/src/auth-session-payload.ts new file mode 100644 index 0000000..28e7898 --- /dev/null +++ b/website/server/src/auth-session-payload.ts @@ -0,0 +1,79 @@ +export interface SessionPayloadMergeCapable { + mergeIntoAccessTokenPayload(payload: Record): Promise +} + +export interface SessionPayloadUserEnvelope { + emails: string[] +} + +export interface SessionPayloadResponseEnvelope { + status?: string + session?: SessionPayloadMergeCapable + user?: SessionPayloadUserEnvelope +} + +function readPrimaryEmail(response: SessionPayloadResponseEnvelope) { + return String(response.user?.emails?.[0] || '').trim().toLowerCase() +} + +async function stampDefaultSessionPayload( + response: SessionPayloadResponseEnvelope, + { + defaultPlan, + defaultRole, + }: { + defaultPlan: string + defaultRole: string + }, +) { + if (response.status !== 'OK' || !response.session) { + return + } + + const email = readPrimaryEmail(response) + if (!email) { + return + } + + await response.session.mergeIntoAccessTokenPayload({ + email, + plan: defaultPlan, + role: defaultRole, + }) +} + +export function buildEmailPasswordApiOverrides>( + originalImplementation: T, + { + defaultPlan, + defaultRole, + }: { + defaultPlan: string + defaultRole: string + }, +) { + const typedImplementation = originalImplementation as T & { + signUpPOST?: (input: unknown) => Promise + signInPOST?: (input: unknown) => Promise + } + + return { + ...originalImplementation, + signUpPOST: async (input: unknown) => { + const response = await typedImplementation.signUpPOST!(input) + await stampDefaultSessionPayload(response, { + defaultPlan, + defaultRole, + }) + return response + }, + signInPOST: async (input: unknown) => { + const response = await typedImplementation.signInPOST!(input) + await stampDefaultSessionPayload(response, { + defaultPlan, + defaultRole, + }) + return response + }, + } as T +} diff --git a/website/server/src/billing-state.ts b/website/server/src/billing-state.ts index e476638..cec7f85 100644 --- a/website/server/src/billing-state.ts +++ b/website/server/src/billing-state.ts @@ -3,6 +3,7 @@ import path from 'node:path' export type BillingPlan = 'free' | 'operator' | 'studio' | 'enterprise' export type BillingRole = 'viewer' | 'operator' | 'reviewer' | 'admin' +export type BillingEntitlementSource = 'paddle' | 'manual' export interface BillingEntitlementState { email: string @@ -10,7 +11,7 @@ export interface BillingEntitlementState { role: BillingRole canDownload: boolean accessStatus: string - source: 'paddle' + source: BillingEntitlementSource customerId: string | null subscriptionId: string | null transactionId: string | null @@ -20,6 +21,14 @@ export interface BillingEntitlementState { updatedAt: string } +export interface ManualBillingEntitlementInput { + email: string + plan: BillingPlan + role: BillingRole + canDownload?: boolean + accessStatus?: string +} + interface BillingStateFile { version: 'ht-billing-state/v1' updatedAt: string @@ -413,6 +422,45 @@ function buildNextEntitlementState({ } } +function buildManualEntitlementState({ + existingAccount, + input, + nowIso, +}: { + existingAccount: BillingEntitlementState | null + input: ManualBillingEntitlementInput + nowIso: string +}): BillingEntitlementState { + const normalizedEmail = normalizeEmail(input.email) + const normalizedPlan = normalizePlan(input.plan, 'free') + const normalizedRole = normalizeRole(input.role, 'viewer') + const resolvedCanDownload = + typeof input.canDownload === 'boolean' + ? input.canDownload + : normalizedPlan !== 'free' + const resolvedAccessStatus = String( + input.accessStatus + || (resolvedCanDownload ? 'active' : normalizedPlan === 'free' ? 'free' : 'manual-review'), + ).trim().toLowerCase() + const manualEventId = `manual:${normalizedEmail}:${Date.parse(nowIso)}` + + return { + email: normalizedEmail, + plan: normalizedPlan, + role: normalizedRole, + canDownload: resolvedCanDownload, + accessStatus: resolvedAccessStatus, + source: 'manual', + customerId: existingAccount?.customerId || null, + subscriptionId: existingAccount?.subscriptionId || null, + transactionId: existingAccount?.transactionId || null, + lastEventId: manualEventId, + lastEventType: 'manual.entitlement.set', + lastEventAt: nowIso, + updatedAt: nowIso, + } +} + function applyParsedPaddleEvent( envelope: PaddleEventEnvelope, runtime: BillingStateStoreRuntime, @@ -527,10 +575,34 @@ export function createBillingStateStore({ return Object.keys(loadState().processedEvents).length } + function setManualEntitlement(input: ManualBillingEntitlementInput): BillingEntitlementState { + const normalizedEmail = normalizeEmail(input.email) + if (!normalizedEmail) { + throw new Error('Manual entitlement email is required.') + } + + const state = loadState() + const nowIso = toIsoString(now()) + const existingAccount = state.accounts[normalizedEmail] || null + const nextState = buildManualEntitlementState({ + existingAccount, + input: { + ...input, + email: normalizedEmail, + }, + nowIso, + }) + + state.accounts[normalizedEmail] = nextState + saveState(state) + return nextState + } + return { applyVerifiedPaddleEvent, getEntitlementByEmail, getProcessedEventCount, getStatePath: () => statePath, + setManualEntitlement, } } diff --git a/website/server/src/index.ts b/website/server/src/index.ts index 81fd49d..3b6ae96 100644 --- a/website/server/src/index.ts +++ b/website/server/src/index.ts @@ -11,6 +11,7 @@ import ThirdParty from 'supertokens-node/recipe/thirdparty' import GithubProvider from 'supertokens-node/lib/build/recipe/thirdparty/providers/github' import GoogleProvider from 'supertokens-node/lib/build/recipe/thirdparty/providers/google' import { resolvePublicLaunchStatusSummary } from '../../src/shared/public-launch' +import { buildEmailPasswordApiOverrides } from './auth-session-payload' import { probeSuperTokensCoreHealth } from './auth-health' import { createBillingStateStore, type BillingPlan, type BillingRole } from './billing-state' import { verifyPaddleWebhookSignature } from './paddle-webhook' @@ -225,19 +226,9 @@ const recipeList = [ ], }, override: { - apis: (originalImplementation) => ({ - ...originalImplementation, - signUpPOST: async (input) => { - const response = await originalImplementation.signUpPOST!(input) - if (response.status === 'OK') { - await response.session.mergeIntoAccessTokenPayload({ - email: response.user.emails[0], - plan: DEFAULT_PLAN, - role: DEFAULT_ROLE, - }) - } - return response - }, + apis: (originalImplementation) => buildEmailPasswordApiOverrides(originalImplementation, { + defaultPlan: DEFAULT_PLAN, + defaultRole: DEFAULT_ROLE, }), }, }), diff --git a/website/src/__tests__/App.bootstrap.test.tsx b/website/src/__tests__/App.bootstrap.test.tsx index 6d0db40..04ee5f3 100644 --- a/website/src/__tests__/App.bootstrap.test.tsx +++ b/website/src/__tests__/App.bootstrap.test.tsx @@ -59,7 +59,7 @@ describe('App bootstrap', () => { render() - expect(await screen.findByText('From first solves to 120-cell, HyperTwist keeps the real simulator in the downloadable.')).toBeTruthy() + expect(await screen.findByText('One serious home for classic cubes, 120‑cell, 5D, and deep daily practice.')).toBeTruthy() await waitFor(() => { expect(window.location.pathname).toBe('/') }) diff --git a/website/src/__tests__/DashboardOverviewPage.test.tsx b/website/src/__tests__/DashboardOverviewPage.test.tsx index ca63d68..e311b07 100644 --- a/website/src/__tests__/DashboardOverviewPage.test.tsx +++ b/website/src/__tests__/DashboardOverviewPage.test.tsx @@ -208,7 +208,7 @@ describe('DashboardOverviewPage', () => { expect(screen.getByText('Protected operator quick routes')).toBeTruthy() expect(screen.getByText('Signed-in help lanes')).toBeTruthy() expect(screen.getByText('Protected browser-versus-desktop reality')).toBeTruthy() - expect(screen.getByText('Current input, XR, and settings truth')).toBeTruthy() + expect(screen.getByText('Controls and device support today')).toBeTruthy() expect( screen .getAllByRole('link', { name: 'Open protected launch status' }) @@ -222,7 +222,7 @@ describe('DashboardOverviewPage', () => { expect(screen.getByText(/Magic120Cell dedicated-family training map: passed/i)).toBeTruthy() expect(screen.getByText('First simulator session')).toBeTruthy() expect(screen.getByText('1. Resolve access and choose the right build')).toBeTruthy() - expect(screen.getByText('4. Open the higher-dimensional lanes and read the control boundary honestly')).toBeTruthy() + expect(screen.getByText('4. Open the higher-dimensional families and read the control boundary honestly')).toBeTruthy() expect(screen.getByText('Software workflows after access is resolved')).toBeTruthy() expect(screen.getByText('2. Run a recognition and correction workflow')).toBeTruthy() expect(screen.getByText('Native control and settings roster')).toBeTruthy() @@ -230,7 +230,7 @@ describe('DashboardOverviewPage', () => { expect(screen.getByText('XR groundwork exists, but the full VR lane is not finished')).toBeTruthy() expect(screen.getByText('Desktop rollout follow-through')).toBeTruthy() expect(screen.getByText('Current product-surface map')).toBeTruthy() - expect(screen.getByText('Embedded simulator browser shell')).toBeTruthy() + expect(screen.getByText('Embedded simulator web tools')).toBeTruthy() expect(screen.getByText('Pair desktop access to the browser account')).toBeTruthy() const generateDesktopLinkButtons = screen.getAllByRole('button', { name: /generate desktop-link token/i }) diff --git a/website/src/__tests__/app-route-tree.test.tsx b/website/src/__tests__/app-route-tree.test.tsx index 8be6cdb..78bc080 100644 --- a/website/src/__tests__/app-route-tree.test.tsx +++ b/website/src/__tests__/app-route-tree.test.tsx @@ -156,10 +156,10 @@ describe('AppRouteTree', () => { renderRoute('/') expect(screen.getByText('Loading HyperTwist...')).toBeTruthy() - expect(screen.getByText('Public release shell')).toBeTruthy() - expect(screen.getByText(/public product story, current launch status, and browser-versus-desktop authority map/i)).toBeTruthy() + expect(screen.getByText('Public website')).toBeTruthy() + expect(screen.getByText(/full HyperTwist story, the current access snapshot, and the easiest path into the desktop app/i)).toBeTruthy() expect(await screen.findByText( - 'From first solves to 120-cell, HyperTwist keeps the real simulator in the downloadable.', + 'One serious home for classic cubes, 120‑cell, 5D, and deep daily practice.', {}, { timeout: 3000 }, )).toBeTruthy() @@ -169,18 +169,17 @@ describe('AppRouteTree', () => { renderRoute('/browser') expect(screen.getByText('Browser access guide')).toBeTruthy() - expect(screen.getByText('Web version role')).toBeTruthy() - expect(screen.getByText(/browser-versus-downloadable boundary, protected dashboard handoff, and the current web-lane purpose/i)).toBeTruthy() - expect(await screen.findByText('The browser version exists to support the downloadable, not replace it.')).toBeTruthy() + expect(screen.getByText('Browser companion')).toBeTruthy() + expect(screen.getByText(/website, account access, and desktop app work together/i)).toBeTruthy() + expect(await screen.findByText('The website gets you in. The desktop app becomes the training room.')).toBeTruthy() }) it('renders the help-center page through the real public route tree', async () => { renderRoute('/help') - expect(screen.getByText('Help center')).toBeTruthy() - expect(screen.getByText('Operator knowledge base')).toBeTruthy() - expect(screen.getByText(/onboarding, control truth, browser-to-desktop guidance, and rollout-safe troubleshooting/i)).toBeTruthy() - expect(await screen.findByText('Production-grade help for the routes, runtime, and rollout you actually have.')).toBeTruthy() + expect(screen.getAllByText('Help center').length).toBeGreaterThan(0) + expect(screen.getByText(/setup, controls, downloads, and practical troubleshooting/i)).toBeTruthy() + expect(await screen.findByText('Practical help for setup, controls, downloads, and launch.')).toBeTruthy() }) it('renders the pricing page through the real public route tree', async () => { @@ -191,8 +190,8 @@ describe('AppRouteTree', () => { it('renders the public feature-atlas page through the real public route tree', async () => { renderRoute('/features') - expect(await screen.findByText('Feature truth without the guesswork.')).toBeTruthy() - expect(screen.getByText('How to read the product truth')).toBeTruthy() + expect(await screen.findByText('A deep training toolkit, not just a timer.')).toBeTruthy() + expect(screen.getByText('How to read this feature map')).toBeTruthy() }) it('renders the download page through the real public route tree', async () => { @@ -203,25 +202,24 @@ describe('AppRouteTree', () => { it('renders the getting-started page through the real public route tree', async () => { renderRoute('/getting-started') - expect(screen.getByText('Getting started')).toBeTruthy() - expect(screen.getByText('Operator onboarding')).toBeTruthy() - expect(screen.getByText(/first-session quickstart, browser-to-desktop pairing flow, and the current desktop-first runtime boundary/i)).toBeTruthy() - expect(await screen.findByText('Start in the browser. Train in the desktop runtime.')).toBeTruthy() + expect(screen.getAllByText('Getting started').length).toBeGreaterThan(0) + expect(screen.getByText(/first-session path from account setup to the desktop app/i)).toBeTruthy() + expect(await screen.findByText('The first serious HyperTwist session')).toBeTruthy() }) it('renders the launch-status page through the real public route tree', async () => { renderRoute('/launch-status') expect(screen.getByText('Launch status')).toBeTruthy() - expect(screen.getByText('Launch authority')).toBeTruthy() - expect(screen.getByText(/canonical public launch-readiness checklist, release status, and early-access authority map/i)).toBeTruthy() + expect(screen.getByText('Access status')).toBeTruthy() + expect(screen.getByText(/current availability, release progress, and access options/i)).toBeTruthy() expect(await screen.findByText('See how public pages, account access, and desktop delivery work together.')).toBeTruthy() }) it('renders the login page through the real public route tree', async () => { renderRoute('/login?next=%2Fapp%2Fdownloads') - expect(screen.getByText('Browser account access')).toBeTruthy() - expect(screen.getByText(/safe next-step routing, and protected release continuity/i)).toBeTruthy() + expect(screen.getByText('Account access')).toBeTruthy() + expect(screen.getByText(/sign-in, account access, and the path into your dashboard and downloads/i)).toBeTruthy() expect(await screen.findByText('Log in to HyperTwist')).toBeTruthy() expect(screen.getByRole('link', { name: /create an account/i }).getAttribute('href')).toBe('/register?next=%2Fapp%2Fdownloads') }) diff --git a/website/src/__tests__/download-center-page.test.tsx b/website/src/__tests__/download-center-page.test.tsx index b92d865..2cd4c7a 100644 --- a/website/src/__tests__/download-center-page.test.tsx +++ b/website/src/__tests__/download-center-page.test.tsx @@ -201,7 +201,7 @@ describe('DownloadCenterPage', () => { expect(screen.getByText('First launch follow-through')).toBeTruthy() expect(screen.getByText('Verify the current training lanes')).toBeTruthy() expect(screen.getByText('Protected browser-versus-desktop reality')).toBeTruthy() - expect(screen.getByText('What the desktop runtime is for')).toBeTruthy() + expect(screen.getByText('Why the desktop app exists')).toBeTruthy() expect(screen.getByText('Download and rollout escalation')).toBeTruthy() expect(screen.getByText('Current product-surface map')).toBeTruthy() expect(await screen.findByText('Version: 1.0.0')).toBeTruthy() diff --git a/website/src/__tests__/protected-app-pages.test.tsx b/website/src/__tests__/protected-app-pages.test.tsx index f01fc05..e9cfda0 100644 --- a/website/src/__tests__/protected-app-pages.test.tsx +++ b/website/src/__tests__/protected-app-pages.test.tsx @@ -197,9 +197,9 @@ describe('protected app pages', () => { expect(screen.getByText('Packaged validation passed')).toBeTruthy() expect(screen.getByText(/Magic120Cell dedicated-family training map: passed/i)).toBeTruthy() expect(screen.getByText('Protected browser-versus-desktop reality')).toBeTruthy() - expect(screen.getByText('Why the browser is intentionally narrower')).toBeTruthy() + expect(screen.getByText('Why the website feels fast and focused')).toBeTruthy() expect(screen.getByText('Desktop workflows behind the browser handoff')).toBeTruthy() - expect(screen.getByText('4. Open the higher-dimensional family lanes')).toBeTruthy() + expect(screen.getByText('4. Open the higher-dimensional families')).toBeTruthy() expect(screen.getByText('Native control and XR boundary')).toBeTruthy() expect(screen.getByText('Shipped classic control profile')).toBeTruthy() expect(await screen.findByText(byExactTextContent('Auth runtime mode: public', 'LI'))).toBeTruthy() @@ -395,12 +395,12 @@ describe('protected app pages', () => { expect(screen.getByText('What the downloaded software already supports')).toBeTruthy() expect(screen.getByText('3. Review replay, coaching, and analytics')).toBeTruthy() expect(screen.getByText('Protected browser-versus-desktop reality')).toBeTruthy() - expect(screen.getByText('What the desktop runtime is for')).toBeTruthy() + expect(screen.getByText('Why the desktop app exists')).toBeTruthy() expect(screen.getByRole('link', { name: 'Open account' }).getAttribute('href')).toBe('/app/account') expect(screen.getAllByRole('link', { name: 'Open browser access' }).every((link) => link.getAttribute('href') === '/app/browser-access')).toBe(true) expect(screen.getByText('Download and rollout escalation')).toBeTruthy() expect(screen.getByText('Current product-surface map')).toBeTruthy() - expect(screen.getByText('Protected browser dashboard')).toBeTruthy() + expect(screen.getByText('Signed-in dashboard')).toBeTruthy() expect(screen.getAllByRole('link', { name: 'Protected launch status' }).every((link) => link.getAttribute('href') === '/app/launch-status')).toBe(true) expect(screen.getByRole('link', { name: 'Protected notices' }).getAttribute('href')).toBe('/app/notices') expect(screen.getByRole('link', { name: 'Public notices' }).getAttribute('href')).toBe('/open-source-notices') @@ -420,7 +420,7 @@ describe('protected app pages', () => { expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() expect(screen.getByText('Protected browser-versus-desktop reality')).toBeTruthy() - expect(screen.getByText('Why the browser is intentionally narrower')).toBeTruthy() + expect(screen.getByText('Why the website feels fast and focused')).toBeTruthy() expect(screen.getByText('Current simulator control ownership')).toBeTruthy() expect(screen.getByText('Current release action')).toBeTruthy() expect(screen.getByRole('link', { name: 'Download Windows package' }).getAttribute('href')).toBe('https://downloads.hypertwist.app/windows.exe') @@ -449,7 +449,7 @@ describe('protected app pages', () => { expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() expect(screen.getByText('Protected browser-versus-desktop reality')).toBeTruthy() - expect(screen.getByText('What the desktop runtime is for')).toBeTruthy() + expect(screen.getByText('Why the desktop app exists')).toBeTruthy() expect(await screen.findAllByText(byExactTextContent('Configured release targets: 1/2', 'LI'))).toHaveLength(1) expect(screen.getByText(byExactTextContent('Public repository/notices URL: https://github.com/hypertwist/hypertwist', 'LI'))).toBeTruthy() expect(screen.getByText(byExactTextContent('Corresponding-source URL: https://hypertwist.app/open-source/source.zip', 'LI'))).toBeTruthy() diff --git a/website/src/__tests__/public-auth-pages.test.tsx b/website/src/__tests__/public-auth-pages.test.tsx index 60958fa..90b8222 100644 --- a/website/src/__tests__/public-auth-pages.test.tsx +++ b/website/src/__tests__/public-auth-pages.test.tsx @@ -206,12 +206,12 @@ describe('public auth and download pages', () => { const registerLink = screen.getByRole('link', { name: /create an account/i }) expect(registerLink.getAttribute('href')).toBe('/register?next=%2Fapp') - expect(screen.getByText('Protected operator dashboard')).toBeTruthy() - expect(screen.getAllByText(/After sign-in you will continue to the protected operator dashboard/i).length).toBeGreaterThan(0) + expect(screen.getAllByText('Signed-in dashboard').length).toBeGreaterThan(0) + expect(screen.getAllByText(/After sign-in you will continue to the signed-in dashboard/i).length).toBeGreaterThan(0) expect(screen.getByText('Browser account access does not replace the simulator.')).toBeTruthy() - expect(screen.getByText('Current input, XR, and settings truth')).toBeTruthy() - expect(screen.getByText('Protected browser dashboard')).toBeTruthy() - expect(screen.getByText('Native Unreal desktop runtime')).toBeTruthy() + expect(screen.getByText('Controls and device support today')).toBeTruthy() + expect(screen.getAllByText('Signed-in dashboard').length).toBeGreaterThan(0) + expect(screen.getAllByText('Desktop simulator').length).toBeGreaterThan(0) expect(screen.getByText('What the desktop runtime is for once you are signed in')).toBeTruthy() expect(screen.getByText('1. Run a classic-cube training session')).toBeTruthy() @@ -234,12 +234,12 @@ describe('public auth and download pages', () => { const loginLink = screen.getByRole('link', { name: 'Log in' }) expect(loginLink.getAttribute('href')).toBe('/login?next=%2Fapp%2Fdownloads%3Fplatform%3Dwindows') - expect(screen.getByText('Protected Windows release lane')).toBeTruthy() - expect(screen.getAllByText(/After sign-in you will continue to the protected Windows download center/i).length).toBeGreaterThan(0) + expect(screen.getByText('Signed-in Windows downloads')).toBeTruthy() + expect(screen.getAllByText(/After sign-in you will continue to the signed-in Windows download center/i).length).toBeGreaterThan(0) expect(screen.getByText('Browser account access does not replace the simulator.')).toBeTruthy() - expect(screen.getByText('Why the browser is intentionally narrower')).toBeTruthy() - expect(screen.getByText('Protected browser dashboard')).toBeTruthy() - expect(screen.getByText('Native Unreal desktop runtime')).toBeTruthy() + expect(screen.getByText('Why the website feels fast and focused')).toBeTruthy() + expect(screen.getAllByText('Signed-in dashboard').length).toBeGreaterThan(0) + expect(screen.getAllByText('Desktop simulator').length).toBeGreaterThan(0) expect(screen.getByText('What the desktop runtime is for once you are signed in')).toBeTruthy() expect(screen.getByText('2. Run a recognition and correction workflow')).toBeTruthy() @@ -295,13 +295,13 @@ describe('public auth and download pages', () => { expect(screen.getByText(/Account access can continue through the available browser-auth lane./i)).toBeTruthy() expect(screen.getByText('What still works')).toBeTruthy() - expect(screen.getByText('What stays intentionally bounded')).toBeTruthy() - expect(screen.getByText('Recommended recovery order')).toBeTruthy() + expect(screen.getByText('What may still need follow-through')).toBeTruthy() + expect(screen.getByText('Best next step')).toBeTruthy() expect(screen.getByText('Auth runtime setting pending: VITE_SUPERTOKENS_API_DOMAIN')).toBeTruthy() expect(screen.getByText('VITE_AUTH_API_BASE_URL not configured; same-origin auth fallback remains active.')).toBeTruthy() expect(screen.getByText('Browser account access does not replace the simulator.')).toBeTruthy() expect(screen.getByRole('link', { name: 'Open support' }).getAttribute('href')).toBe('/support?topic=operator-access') - expect(screen.getByText('Protected operator dashboard')).toBeTruthy() + expect(screen.getAllByText('Signed-in dashboard').length).toBeGreaterThan(0) expect(screen.getByText('What the desktop runtime is for once you are signed in')).toBeTruthy() }) diff --git a/website/src/__tests__/public-marketing-pages.test.tsx b/website/src/__tests__/public-marketing-pages.test.tsx index c1a8d17..9d4e47b 100644 --- a/website/src/__tests__/public-marketing-pages.test.tsx +++ b/website/src/__tests__/public-marketing-pages.test.tsx @@ -274,8 +274,8 @@ describe('public marketing pages', () => { expect(screen.getByText('What the installed runtime already owns')).toBeTruthy() expect(screen.getByText('Higher-dimensional family guide')).toBeTruthy() expect(screen.getByText('Current input and runtime control truth')).toBeTruthy() - expect(screen.getByText('Why HyperTwist keeps both a website and a desktop runtime')).toBeTruthy() - expect(screen.getByText('Why the browser is intentionally narrower')).toBeTruthy() + expect(screen.getByText('Why HyperTwist gives you both a website and a desktop app')).toBeTruthy() + expect(screen.getByText('Why the website feels fast and focused')).toBeTruthy() expect(screen.getByRole('heading', { name: 'Browser account access methods' })).toBeTruthy() expect(screen.getByText('Auth methods ready')).toBeTruthy() expect(screen.getByText('Email and password')).toBeTruthy() @@ -283,20 +283,20 @@ describe('public marketing pages', () => { expect(screen.getByText('ORCID sign-in')).toBeTruthy() expect(screen.queryByText('Google sign-in')).toBeNull() expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() - const downloadDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next release move' }) + const downloadDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next best step' }) const downloadDecisionGuideSection = downloadDecisionGuideHeading.closest('section') expect(downloadDecisionGuideSection).toBeTruthy() - expect(within(downloadDecisionGuideSection as HTMLElement).getByText('Need the protected desktop-download lane?')).toBeTruthy() - expect(within(downloadDecisionGuideSection as HTMLElement).getByText('Need notices, corresponding source, or release follow-through?')).toBeTruthy() + expect(within(downloadDecisionGuideSection as HTMLElement).getByText('Need the desktop download?')).toBeTruthy() + expect(within(downloadDecisionGuideSection as HTMLElement).getByText('Need legal details, release notes, or source links?')).toBeTruthy() expect(screen.getByText('First launch and desktop setup')).toBeTruthy() expect(screen.getByText('First-session verification checklist')).toBeTruthy() expect(screen.getByText('Verify the higher-dimensional lane you plan to use')).toBeTruthy() - expect(screen.getByText('Offline operator manual')).toBeTruthy() - expect(screen.getByRole('link', { name: 'Download offline operator manual' }).getAttribute('href')).toBe('/manual/hypertwist-operator-manual.md') + expect(screen.getAllByText('Offline desktop guide').length).toBeGreaterThan(0) + expect(screen.getByRole('link', { name: 'Download offline desktop guide' }).getAttribute('href')).toBe('/manual/hypertwist-operator-manual.md') expect(screen.getByText('First desktop session after install')).toBeTruthy() expect(screen.getByText('2. Pair the installed runtime without password reuse')).toBeTruthy() expect(screen.getByText('Digital delivery workflow')).toBeTruthy() - expect(screen.getByText('Protected entitlement handoff')).toBeTruthy() + expect(screen.getByText('Private download handoff')).toBeTruthy() expect(screen.getByText('Distribution doctrine')).toBeTruthy() expect(screen.getByText('Public pages are distribution surfaces')).toBeTruthy() expect(screen.getByText('Release references and source availability')).toBeTruthy() @@ -311,8 +311,8 @@ describe('public marketing pages', () => { expect(screen.getByText('SHA-256: abc123')).toBeTruthy() expect(screen.getAllByText('Packaged validation passed').length).toBeGreaterThan(0) expect(screen.getAllByText(/Magic120Cell dedicated-family training map: passed/i).length).toBeGreaterThan(0) - expect(screen.getByText('Generates desktop-link tokens for safe browser-to-desktop handoff')).toBeTruthy() - expect(screen.getByText('Owns the device/runtime integrations the public website does not claim')).toBeTruthy() + expect(screen.getByText('Generates desktop-link tokens for safe website-to-desktop pairing.')).toBeTruthy() + expect(screen.getByText('Owns the device integrations the public website does not claim.')).toBeTruthy() expect(document.title).toBe('Download HyperTwist desktop | HyperTwist') expect(document.head.querySelector('meta[property="og:url"]')?.getAttribute('content')).toBe('https://hypertwist.app/download') }) @@ -361,7 +361,7 @@ describe('public marketing pages', () => { expect(await screen.findByText(/Release service recovery/i)).toBeTruthy() expect(screen.getByText(/direct package delivery stays intentionally withheld until that authority returns/i)).toBeTruthy() expect(screen.getByText('What stays intentionally withheld')).toBeTruthy() - expect(screen.getByRole('link', { name: 'Open protected download center' }).getAttribute('href')).toBe('/app/downloads?platform=windows') + expect(screen.getAllByRole('link', { name: 'Open protected download center' }).some((link) => link.getAttribute('href') === '/app/downloads?platform=windows')).toBe(true) expect(screen.getByRole('link', { name: 'Open support' }).getAttribute('href')).toBe('/support?topic=operator-access') }) @@ -461,15 +461,15 @@ describe('public marketing pages', () => { renderWithProviders(, ['/']) - expect(screen.getByText('Current public site status')).toBeTruthy() + expect(screen.getByText('Current access snapshot')).toBeTruthy() expect(await screen.findByText('Public website and release access')).toBeTruthy() expect(screen.getAllByText('Account-gated early access').length).toBeGreaterThan(0) - expect(screen.getByText('Why HyperTwist keeps both a website and a desktop runtime')).toBeTruthy() + expect(screen.getByText('Why HyperTwist gives you both a website and a desktop app')).toBeTruthy() expect(screen.getByText('Common browser-versus-desktop questions')).toBeTruthy() - expect(screen.getByText('If the desktop app is primary, why keep the web version?')).toBeTruthy() - expect(screen.getByText(/It is intentionally inferior for the core simulator job/i)).toBeTruthy() - expect(screen.getByText('What the website is for')).toBeTruthy() - expect(screen.getByText('Current input, XR, and settings truth')).toBeTruthy() + expect(screen.getByText('What is the website actually for?')).toBeTruthy() + expect(screen.getByText('The desktop app stays primary because that is where practice starts to feel rich, responsive, and worth returning to every day.')).toBeTruthy() + expect(screen.getByText('Why the website exists')).toBeTruthy() + expect(screen.getByText('Controls and device support today')).toBeTruthy() expect(screen.getAllByText('Account-gated early access').length).toBeGreaterThan(0) expect(screen.getByText('Subscription access: managed on the website/dashboard and handed to the downloadable through desktop-link pairing.')).toBeTruthy() expect(screen.getByRole('heading', { name: 'Browser account access methods' })).toBeTruthy() @@ -480,23 +480,23 @@ describe('public marketing pages', () => { expect(screen.queryByText('Google sign-in')).toBeNull() expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() - const homeDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next release move' }) + const homeDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next best step' }) const homeDecisionGuideSection = homeDecisionGuideHeading.closest('section') expect(homeDecisionGuideSection).toBeTruthy() - expect(within(homeDecisionGuideSection as HTMLElement).getByText('Need the protected desktop-download lane?')).toBeTruthy() - expect(within(homeDecisionGuideSection as HTMLElement).getByText('Need plan selection, billing, or operator provisioning?')).toBeTruthy() + expect(within(homeDecisionGuideSection as HTMLElement).getByText('Need the desktop download?')).toBeTruthy() + expect(within(homeDecisionGuideSection as HTMLElement).getByText('Need pricing, billing, or subscription help?')).toBeTruthy() expect(screen.getByText('Release references and source availability')).toBeTruthy() expect(screen.getByRole('link', { name: 'https://docs.hypertwist.app' })).toBeTruthy() expect(screen.getByText('How a real first session flows')).toBeTruthy() expect(screen.getByText('What the first serious session should look like')).toBeTruthy() expect(screen.getByText('1. Resolve access and choose the right build')).toBeTruthy() expect(screen.getByText('Which public page should you open next?')).toBeTruthy() - expect(screen.getByText('Offline operator manual')).toBeTruthy() - expect(screen.getByRole('link', { name: 'Download offline operator manual' }).getAttribute('href')).toBe('/manual/hypertwist-operator-manual.md') + expect(screen.getAllByText('Offline desktop guide').length).toBeGreaterThan(0) + expect(screen.getByRole('link', { name: 'Download offline desktop guide' }).getAttribute('href')).toBe('/manual/hypertwist-operator-manual.md') expect(screen.getByText('Launch status')).toBeTruthy() expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() - expect(screen.getByText('Move into the protected dashboard')).toBeTruthy() - expect(screen.getAllByText('Current surface authority map').length).toBeGreaterThan(0) + expect(screen.getByText('Open your account dashboard')).toBeTruthy() + expect(screen.getAllByText('Where each part of HyperTwist lives').length).toBeGreaterThan(0) expect(screen.getAllByText('Native Unreal desktop runtime').length).toBeGreaterThan(0) }) @@ -603,25 +603,25 @@ describe('public marketing pages', () => { renderWithProviders(, ['/about']) expect(screen.getByText('How a real HyperTwist session unfolds')).toBeTruthy() - expect(screen.getByText('Why HyperTwist keeps both a website and a desktop runtime')).toBeTruthy() + expect(screen.getByText('Why HyperTwist gives you both a website and a desktop app')).toBeTruthy() expect(screen.getAllByText('Common browser-versus-desktop questions').length).toBeGreaterThan(0) - expect(screen.getByText('Is the simulator fully in the browser?')).toBeTruthy() - expect(screen.getByText(/The current shipping lane is desktop-first and Unreal-backed/i)).toBeTruthy() - expect(screen.getByText('What the desktop runtime is for')).toBeTruthy() + expect(screen.getByText('Can I use HyperTwist entirely in my browser?')).toBeTruthy() + expect(screen.getByText(/current shipping product is desktop-first and Unreal-backed/i)).toBeTruthy() + expect(screen.getByText('Why the desktop app exists')).toBeTruthy() expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() - expect(screen.getByText('Stay on the public website')).toBeTruthy() - const aboutDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next release move' }) + expect(screen.getByText('Stay on the website')).toBeTruthy() + const aboutDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next best step' }) const aboutDecisionGuideSection = aboutDecisionGuideHeading.closest('section') expect(aboutDecisionGuideSection).toBeTruthy() - expect(within(aboutDecisionGuideSection as HTMLElement).getByText('Need account state, pairing, or protected browser follow-through?')).toBeTruthy() - expect(within(aboutDecisionGuideSection as HTMLElement).getByText('Need plan selection, billing, or operator provisioning?')).toBeTruthy() + expect(within(aboutDecisionGuideSection as HTMLElement).getByText('Need account access, pairing, or dashboard help?')).toBeTruthy() + expect(within(aboutDecisionGuideSection as HTMLElement).getByText('Need pricing, billing, or subscription help?')).toBeTruthy() expect(screen.getByText('Current desktop control and headset truth')).toBeTruthy() expect(screen.getByText('Selectable control and settings roster')).toBeTruthy() expect(screen.getByText('Shipped classic control profile')).toBeTruthy() - expect(screen.getByText('Generates desktop-link tokens for safe browser-to-desktop handoff')).toBeTruthy() - expect(screen.getByText('Would need its own runtime quality, backend contract, and product proof before launch')).toBeTruthy() + expect(screen.getByText('Generates desktop-link tokens for safe website-to-desktop pairing.')).toBeTruthy() + expect(screen.getByText('Future browser-only simulator')).toBeTruthy() expect(screen.getByText('Release and deployment maturity')).toBeTruthy() - expect(screen.getByText('Current public rollout state')).toBeTruthy() + expect(screen.getByText('Current public access state')).toBeTruthy() expect(screen.getByText('About-page launch and release access')).toBeTruthy() expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() @@ -725,31 +725,31 @@ describe('public marketing pages', () => { renderWithProviders(, ['/features']) - expect(screen.getByText('Feature truth without the guesswork.')).toBeTruthy() - expect(screen.getByText('How to read the product truth')).toBeTruthy() - expect(screen.getByText('Implemented now')).toBeTruthy() + expect(screen.getByText('A deep training toolkit, not just a timer.')).toBeTruthy() + expect(screen.getByText('How to read this feature map')).toBeTruthy() + expect(screen.getByText('Available today')).toBeTruthy() expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() - expect(screen.getByText('Why HyperTwist keeps both a website and a desktop runtime')).toBeTruthy() - expect(screen.getByText('Current input, XR, and settings truth')).toBeTruthy() - expect(screen.getAllByText('Current surface authority map').length).toBeGreaterThan(0) - expect(screen.getAllByText('Embedded simulator browser shell').length).toBeGreaterThan(0) - expect(screen.getByText('Current shipped capability')).toBeTruthy() + expect(screen.getByText('Why HyperTwist gives you both a website and a desktop app')).toBeTruthy() + expect(screen.getByText('Controls and device support today')).toBeTruthy() + expect(screen.getAllByText('Where everything happens').length).toBeGreaterThan(0) + expect(screen.getAllByText('Embedded simulator web tools').length).toBeGreaterThan(0) + expect(screen.getAllByText('What you can use today').length).toBeGreaterThan(0) expect(screen.getByText('Current selectable control roster')).toBeTruthy() expect(screen.getAllByText('Selectable immersive and family-specific settings').length).toBeGreaterThan(0) expect(screen.getAllByText('XR reopen requirements').length).toBeGreaterThan(0) expect(screen.getByText('The remaining reopen requirement is Windows packaged controller validation with controller truth on the shipping lane rather than only editor-time or config-only confidence.')).toBeTruthy() - expect(screen.getByText('Runtime control guide')).toBeTruthy() + expect(screen.getByText('Controls guide')).toBeTruthy() expect(screen.getByText('Native diagnostics check')).toBeTruthy() expect(screen.getByText('Common capability questions')).toBeTruthy() - expect(screen.getByText('If the desktop app is primary, why keep the web version?')).toBeTruthy() - expect(screen.getByText('Is VR/controller support already fully finished?')).toBeTruthy() - expect(screen.getByText('Current public rollout state')).toBeTruthy() + expect(screen.getByText('What is the website actually for?')).toBeTruthy() + expect(screen.getByText('Is VR support already complete?')).toBeTruthy() + expect(screen.getByText('Current availability')).toBeTruthy() expect(screen.getByText('Public feature and access status')).toBeTruthy() - const featuresDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next release move' }) + const featuresDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next best step' }) const featuresDecisionGuideSection = featuresDecisionGuideHeading.closest('section') expect(featuresDecisionGuideSection).toBeTruthy() - expect(within(featuresDecisionGuideSection as HTMLElement).getByText('Need the protected desktop-download lane?')).toBeTruthy() - expect(within(featuresDecisionGuideSection as HTMLElement).getByText('Need plan selection, billing, or operator provisioning?')).toBeTruthy() + expect(within(featuresDecisionGuideSection as HTMLElement).getByText('Need the desktop download?')).toBeTruthy() + expect(within(featuresDecisionGuideSection as HTMLElement).getByText('Need pricing, billing, or subscription help?')).toBeTruthy() expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() expect(screen.getByText('Release references and source availability')).toBeTruthy() @@ -931,22 +931,22 @@ describe('public marketing pages', () => { expect(screen.getAllByText('Current input and runtime control truth').length).toBeGreaterThan(0) expect(screen.getByText('The current host decision remains desktop-first for broader native OpenXR/controller rollout until Windows packaged controller validation with controller truth is complete.')).toBeTruthy() expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() - const pricingDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next release move' }) + const pricingDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next best step' }) const pricingDecisionGuideSection = pricingDecisionGuideHeading.closest('section') expect(pricingDecisionGuideSection).toBeTruthy() - expect(within(pricingDecisionGuideSection as HTMLElement).getByText('Need plan selection, billing, or operator provisioning?')).toBeTruthy() - expect(within(pricingDecisionGuideSection as HTMLElement).getByText('Need account state, pairing, or protected browser follow-through?')).toBeTruthy() - expect(screen.getByText('Why HyperTwist keeps both a website and a desktop runtime')).toBeTruthy() - expect(screen.getByText('Use the desktop runtime')).toBeTruthy() - expect(screen.getByText('Current input, XR, and settings truth')).toBeTruthy() + expect(within(pricingDecisionGuideSection as HTMLElement).getByText('Need pricing, billing, or subscription help?')).toBeTruthy() + expect(within(pricingDecisionGuideSection as HTMLElement).getByText('Need account access, pairing, or dashboard help?')).toBeTruthy() + expect(screen.getByText('Why HyperTwist gives you both a website and a desktop app')).toBeTruthy() + expect(screen.getByText('The desktop app stays primary because that is where practice starts to feel rich, responsive, and worth returning to every day.')).toBeTruthy() + expect(screen.getByText('Controls and device support today')).toBeTruthy() expect(screen.getByRole('heading', { name: 'Browser account access methods' })).toBeTruthy() expect(screen.getByText('Auth methods ready')).toBeTruthy() expect(screen.getByText('Email and password')).toBeTruthy() expect(screen.getByText('GitHub sign-in')).toBeTruthy() expect(screen.getByText('ORCID sign-in')).toBeTruthy() expect(screen.queryByText('Google sign-in')).toBeNull() - expect(screen.getByText('Shows account, auth, billing, and release readiness status')).toBeTruthy() - expect(screen.getByText('Owns recognition, replay, coaching, and packaged training behavior')).toBeTruthy() + expect(screen.getByText('Shows account, auth, billing, and release status.')).toBeTruthy() + expect(screen.getByText('Owns recognition, replay, coaching, and packaged training behavior.')).toBeTruthy() expect(screen.getByText('Commercial distribution doctrine')).toBeTruthy() expect(screen.getByText('Public pages are distribution surfaces')).toBeTruthy() expect(screen.getByText('Higher-dimensional runtime ownership')).toBeTruthy() @@ -1022,23 +1022,23 @@ describe('public marketing pages', () => { }) renderWithProviders(, ['/support?topic=launch-readiness']) - expect(screen.getAllByText('Selected help lane').length).toBeGreaterThan(0) + expect(screen.getAllByText('Selected help topic').length).toBeGreaterThan(0) expect(screen.getAllByText('Launch readiness').length).toBeGreaterThan(0) - expect(screen.getAllByText(/turning early access into a public launch/i).length).toBeGreaterThan(0) - expect(screen.getByText('Selected lane next steps')).toBeTruthy() - const selectedLaneHeading = screen.getByRole('heading', { name: 'Selected lane next steps' }) + expect(screen.getAllByText(/current website, pricing, download, and legal status before a wider public launch/i).length).toBeGreaterThan(0) + expect(screen.getByText('Selected topic next steps')).toBeTruthy() + const selectedLaneHeading = screen.getByRole('heading', { name: 'Selected topic next steps' }) const selectedLaneSection = selectedLaneHeading.closest('section') expect(selectedLaneSection).toBeTruthy() - expect(within(selectedLaneSection as HTMLElement).getByText('Confirm public launch status, operator/studio checkout status, and support contact first.')).toBeTruthy() - expect(within(selectedLaneSection as HTMLElement).getByRole('link', { name: 'Sign in for protected release lane' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Fdownloads%3Fplatform%3Dwindows') - expect(within(selectedLaneSection as HTMLElement).getByRole('link', { name: 'Sign in for protected notices' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Fnotices') + expect(within(selectedLaneSection as HTMLElement).getByText('Confirm public launch status, checkout readiness, and support contact first.')).toBeTruthy() + expect(within(selectedLaneSection as HTMLElement).getByRole('link', { name: 'Sign in for desktop downloads' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Fdownloads%3Fplatform%3Dwindows') + expect(within(selectedLaneSection as HTMLElement).getByRole('link', { name: 'Sign in for notices' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Fnotices') expect(within(selectedLaneSection as HTMLElement).getByRole('link', { name: 'Open pricing' }).getAttribute('href')).toBe('/pricing') - expect(screen.getByText('If the desktop app is primary, why keep the web version?')).toBeTruthy() - expect(screen.getByText('Is VR/controller support already fully finished?')).toBeTruthy() + expect(screen.getByText('What is the website actually for?')).toBeTruthy() + expect(screen.getByText('Is VR support already complete?')).toBeTruthy() expect(screen.getByText('Do higher-dimensional selector choices persist between sessions?')).toBeTruthy() expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() - expect(screen.getByText('Why HyperTwist keeps both a website and a desktop runtime')).toBeTruthy() - expect(screen.getByText('Why the browser is intentionally narrower')).toBeTruthy() + expect(screen.getByText('Why HyperTwist gives you both a website and a desktop app')).toBeTruthy() + expect(screen.getByText('Why the website feels fast and focused')).toBeTruthy() expect(screen.getByText('Browser and desktop responsibilities')).toBeTruthy() expect(screen.getByRole('heading', { name: 'Current browser sign-in methods' })).toBeTruthy() expect(screen.getByText('Auth methods ready')).toBeTruthy() @@ -1046,7 +1046,7 @@ describe('public marketing pages', () => { expect(screen.getByText('GitHub sign-in')).toBeTruthy() expect(screen.getByText('ORCID sign-in')).toBeTruthy() expect(screen.queryByText('Google sign-in')).toBeNull() - expect(screen.getByText('Shows account, auth, billing, and release readiness status')).toBeTruthy() + expect(screen.getByText('Shows account, auth, billing, and release status.')).toBeTruthy() expect(screen.getByText('Support lanes')).toBeTruthy() expect(screen.getByText('Issue reporting checklist')).toBeTruthy() expect(screen.getByText('Account, pairing, or entitlement issue report')).toBeTruthy() @@ -1058,19 +1058,19 @@ describe('public marketing pages', () => { expect(screen.getByText('Current support-facing launch access')).toBeTruthy() expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() - const decisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next release move' }) + const decisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next best step' }) const decisionGuideSection = decisionGuideHeading.closest('section') expect(decisionGuideSection).toBeTruthy() - expect(within(decisionGuideSection as HTMLElement).getByText('Need the protected desktop-download lane?')).toBeTruthy() - expect(within(decisionGuideSection as HTMLElement).getByText('Need plan selection, billing, or operator provisioning?')).toBeTruthy() - expect(within(decisionGuideSection as HTMLElement).getByText('Need account state, pairing, or protected browser follow-through?')).toBeTruthy() - expect(within(decisionGuideSection as HTMLElement).getByText('Need notices, corresponding source, or release follow-through?')).toBeTruthy() - expect(within(decisionGuideSection as HTMLElement).getByRole('link', { name: 'Sign in for protected browser access' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Fbrowser-access') + expect(within(decisionGuideSection as HTMLElement).getByText('Need the desktop download?')).toBeTruthy() + expect(within(decisionGuideSection as HTMLElement).getByText('Need pricing, billing, or subscription help?')).toBeTruthy() + expect(within(decisionGuideSection as HTMLElement).getByText('Need account access, pairing, or dashboard help?')).toBeTruthy() + expect(within(decisionGuideSection as HTMLElement).getByText('Need legal details, release notes, or source links?')).toBeTruthy() + expect(within(decisionGuideSection as HTMLElement).getByRole('link', { name: 'Sign in for browser access' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Fbrowser-access') expect(within(decisionGuideSection as HTMLElement).getByRole('link', { name: 'Review public notices' }).getAttribute('href')).toBe('/open-source-notices') expect(screen.getByText('Release references and source availability')).toBeTruthy() expect(screen.getByRole('link', { name: 'https://docs.hypertwist.app' })).toBeTruthy() expect(screen.getByText('Digital delivery workflow')).toBeTruthy() - expect(screen.getByText('Post-install operator workflow')).toBeTruthy() + expect(screen.getByText('After-install rhythm')).toBeTruthy() expect(screen.getByText('Privacy and compliance boundary')).toBeTruthy() expect(screen.getByText('Browser identity and billing boundary')).toBeTruthy() expect(screen.getByText('Escalation map')).toBeTruthy() @@ -1135,19 +1135,19 @@ describe('public marketing pages', () => { }) const browserView = renderWithProviders(, ['/browser']) - expect(within(browserView.container).getByText('What the browser version is genuinely for')).toBeTruthy() - expect(within(browserView.container).getByText('Why the downloadable remains much more powerful')).toBeTruthy() + expect(within(browserView.container).getByText('What the website is genuinely great at')).toBeTruthy() + expect(within(browserView.container).getByText('Why the desktop app goes much further')).toBeTruthy() expect(within(browserView.container).getByText('How the browser and downloadable work together')).toBeTruthy() - expect(within(browserView.container).getByText('The browser version exists to support the downloadable, not replace it.')).toBeTruthy() + expect(within(browserView.container).getByText('The website gets you in. The desktop app becomes the training room.')).toBeTruthy() const helpView = renderWithProviders(, ['/help']) expect(within(helpView.container).getByText('What this help center covers')).toBeTruthy() - expect(within(helpView.container).getByText('Pick the right help lane')).toBeTruthy() + expect(within(helpView.container).getByText('Pick the right help path')).toBeTruthy() expect(within(helpView.container).getByText('Current controls and device state')).toBeTruthy() expect(within(helpView.container).getByText('Need escalation instead of guidance?')).toBeTruthy() const contactView = renderWithProviders(, ['/contact']) - expect(within(contactView.container).getByText('Contact lanes')).toBeTruthy() + expect(within(contactView.container).getByText('Contact paths')).toBeTruthy() expect(within(contactView.container).getByText('Primary contact route')).toBeTruthy() expect(within(contactView.container).getByText('What to include in your message')).toBeTruthy() expect(within(contactView.container).getByText('How HyperTwist classifies escalations')).toBeTruthy() @@ -1262,26 +1262,26 @@ describe('public marketing pages', () => { ).toBeTruthy() expect(screen.getAllByText('Support topic quick routes').length).toBeGreaterThan(0) expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() - expect(screen.getByText('Why HyperTwist keeps both a website and a desktop runtime')).toBeTruthy() - expect(screen.getByText('Why the browser is intentionally narrower')).toBeTruthy() + expect(screen.getByText('Why HyperTwist gives you both a website and a desktop app')).toBeTruthy() + expect(screen.getByText('Why the website feels fast and focused')).toBeTruthy() expect(screen.getByText('Recovery and escalation')).toBeTruthy() - expect(screen.getByText('Operator playbooks')).toBeTruthy() + expect(screen.getByText('Training and team playbooks')).toBeTruthy() expect(screen.getByText('Simulator use today')).toBeTruthy() expect(screen.getByText('Higher-dimensional runtime guide')).toBeTruthy() expect(screen.getByText('Current control and device state')).toBeTruthy() expect(screen.getAllByText('Selectable control and settings roster').length).toBeGreaterThan(0) expect(screen.getByText(/3 immersive-intensity presets and 3 reduced-distraction presets/i)).toBeTruthy() - expect(screen.getByText('Deployment readiness snapshot')).toBeTruthy() + expect(screen.getByText('Release snapshot')).toBeTruthy() expect(screen.getAllByText('XR groundwork exists, but the full VR lane is not finished').length).toBeGreaterThan(0) expect(screen.getByText('Higher-dimensional runtime ownership')).toBeTruthy() expect(screen.getByText('Public manual route atlas')).toBeTruthy() expect(screen.getByText('Shipping & payment')).toBeTruthy() - expect(screen.getByText('Offline operator manual')).toBeTruthy() - expect(screen.getByRole('link', { name: 'Download offline operator manual' }).getAttribute('href')).toBe('/manual/hypertwist-operator-manual.md') - expect(screen.getByText('Choose the next release move')).toBeTruthy() - expect(screen.getByText('Need account state, pairing, or protected browser follow-through?')).toBeTruthy() - expect(screen.getByText(/The web lane is not superfluous/i)).toBeTruthy() - expect(screen.getByRole('link', { name: 'Sign in for protected dashboard' }).getAttribute('href')).toBe('/login?next=%2Fapp') + expect(screen.getAllByText('Offline desktop guide').length).toBeGreaterThan(0) + expect(screen.getByRole('link', { name: 'Download offline desktop guide' }).getAttribute('href')).toBe('/manual/hypertwist-operator-manual.md') + expect(screen.getByText('Choose the next best step')).toBeTruthy() + expect(screen.getByText('Need account access, pairing, or dashboard help?')).toBeTruthy() + expect(screen.getByText('Open your account dashboard')).toBeTruthy() + expect(screen.getByRole('link', { name: 'Sign in for dashboard' }).getAttribute('href')).toBe('/login?next=%2Fapp') expect(screen.getByText('Release references and source availability')).toBeTruthy() expect(screen.getByRole('link', { name: 'https://docs.hypertwist.app' })).toBeTruthy() }) @@ -1415,21 +1415,21 @@ describe('public marketing pages', () => { expect(screen.getByText('Current shipped capability')).toBeTruthy() expect(screen.getByText('Native training and coaching core')).toBeTruthy() - expect(screen.getByText('Operator manual')).toBeTruthy() + expect(screen.getByText('How HyperTwist is actually used')).toBeTruthy() expect(screen.getByText('First real desktop session')).toBeTruthy() expect(screen.getByText('Operational verification checklist')).toBeTruthy() expect(screen.getByText('Recovery and degraded-state manual')).toBeTruthy() expect(screen.getByText('Issue reporting checklist')).toBeTruthy() - expect(screen.getByText('Offline operator manual')).toBeTruthy() - expect(screen.getByRole('link', { name: 'Download offline operator manual' }).getAttribute('href')).toBe('/manual/hypertwist-operator-manual.md') + expect(screen.getAllByText('Offline desktop guide').length).toBeGreaterThan(0) + expect(screen.getByRole('link', { name: 'Download offline desktop guide' }).getAttribute('href')).toBe('/manual/hypertwist-operator-manual.md') expect(screen.getByText('Support topic quick routes')).toBeTruthy() - expect(screen.getAllByText('Current surface authority map').length).toBeGreaterThan(0) - expect(screen.getByText('Why HyperTwist keeps both a website and a desktop runtime')).toBeTruthy() - expect(screen.getByText('Why the browser is intentionally narrower')).toBeTruthy() + expect(screen.getAllByText('Where each part of HyperTwist lives').length).toBeGreaterThan(0) + expect(screen.getByText('Why HyperTwist gives you both a website and a desktop app')).toBeTruthy() + expect(screen.getByText('Why the website feels fast and focused')).toBeTruthy() expect(screen.getByText('When to use browser versus desktop')).toBeTruthy() expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() - expect(screen.getAllByText('Protected browser dashboard').length).toBeGreaterThan(0) - expect(screen.getAllByText('1. Start in the browser shell').length).toBeGreaterThan(0) + expect(screen.getAllByText('Signed-in dashboard').length).toBeGreaterThan(0) + expect(screen.getAllByText('1. Start on the website').length).toBeGreaterThan(0) expect(screen.getAllByText('Optional full-browser simulator branch').length).toBeGreaterThan(0) expect(screen.getByText('Simulator manual')).toBeTruthy() expect(screen.getByText('Higher-dimensional family guide')).toBeTruthy() @@ -1438,7 +1438,7 @@ describe('public marketing pages', () => { expect(screen.getAllByText('Selectable control and settings roster').length).toBeGreaterThan(0) expect(screen.getAllByText('Keyboard and mouse ship today').length).toBeGreaterThan(0) expect(screen.getAllByText(/classic-wca-keyboard\/v1/i).length).toBeGreaterThan(0) - expect(screen.getByText('4. Open the higher-dimensional lanes and read the control boundary honestly')).toBeTruthy() + expect(screen.getByText('4. Open the higher-dimensional families and read the control boundary honestly')).toBeTruthy() expect(screen.getByText(/I\/K = R\/R', J\/F = U\/U', H\/G = F\/F'/i)).toBeTruthy() expect(screen.getByText(/bounded OpenXR plugin stack, first-party runtime-owner substrate, and first-party controller settings\/rebinding ownership/i)).toBeTruthy() expect(screen.getByText(/R scramble, H hint, Enter submit, F mode, V hold-to-talk, C cycle voice/i)).toBeTruthy() @@ -1449,13 +1449,13 @@ describe('public marketing pages', () => { expect(screen.getByText('Browser auth degraded or mixed')).toBeTruthy() expect(screen.getByText('Release authority temporarily unavailable')).toBeTruthy() expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() - expect(screen.getByText('Choose the next release move')).toBeTruthy() - expect(screen.getByText('Need the protected desktop-download lane?')).toBeTruthy() - expect(screen.getByText('Need notices, corresponding source, or release follow-through?')).toBeTruthy() + expect(screen.getByText('Choose the next best step')).toBeTruthy() + expect(screen.getByText('Need the desktop download?')).toBeTruthy() + expect(screen.getByText('Need legal details, release notes, or source links?')).toBeTruthy() expect(screen.getByRole('link', { name: 'Review public notices' }).getAttribute('href')).toBe('/open-source-notices') - expect(screen.getByText('Common operator questions')).toBeTruthy() - expect(screen.getByText('If the desktop app is primary, why keep the web version?')).toBeTruthy() - expect(screen.getByText(/it does not own package-validated training behavior, low-latency native input, higher-dimensional packaged execution, or device\/runtime integration authority/i)).toBeTruthy() + expect(screen.getByText('Common questions')).toBeTruthy() + expect(screen.getByText('What is the website actually for?')).toBeTruthy() + expect(screen.getByText('It does not pretend to be the full simulator, the advanced puzzle room, or the device-heavy practice surface.')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() expect(screen.getByText('Release references and source availability')).toBeTruthy() expect(screen.getByRole('link', { name: 'https://docs.hypertwist.app' })).toBeTruthy() @@ -1560,8 +1560,8 @@ describe('public marketing pages', () => { expect(screen.getByText('The first serious HyperTwist session')).toBeTruthy() expect(screen.getByText('Operator path')).toBeTruthy() - expect(screen.getByText('Offline operator manual')).toBeTruthy() - expect(screen.getByRole('link', { name: 'Download offline operator manual' }).getAttribute('href')).toBe('/manual/hypertwist-operator-manual.md') + expect(screen.getAllByText('Offline desktop guide').length).toBeGreaterThan(0) + expect(screen.getByRole('link', { name: 'Download offline desktop guide' }).getAttribute('href')).toBe('/manual/hypertwist-operator-manual.md') expect(screen.getByText('Browser account access methods')).toBeTruthy() expect(screen.getByText('First launch and desktop setup')).toBeTruthy() expect(screen.getByText('First-session verification checklist')).toBeTruthy() @@ -1686,7 +1686,7 @@ describe('public marketing pages', () => { expect(screen.getByText('Access support and escalation lanes')).toBeTruthy() expect(screen.getByText('Choose the next access move')).toBeTruthy() expect(screen.getByText('Release, notice, and support bundle')).toBeTruthy() - expect(screen.getByText('Why access authority stays in the browser shell')).toBeTruthy() + expect(screen.getByText('Why access status lives on the website')).toBeTruthy() expect(screen.getAllByText('Launch readiness').length).toBeGreaterThan(0) expect( screen.getAllByRole('link', { name: 'Open launch status' }).some((link) => link.getAttribute('href') === '/launch-status'), @@ -1797,10 +1797,10 @@ describe('public marketing pages', () => { expect(screen.getByText('Signed-in operator shell now mirrors the native control roster')).toBeTruthy() expect(screen.getByText('Native selector-recall diagnostics hardened and revalidated')).toBeTruthy() expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() - const changelogDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next release move' }) + const changelogDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next best step' }) const changelogDecisionGuideSection = changelogDecisionGuideHeading.closest('section') expect(changelogDecisionGuideSection).toBeTruthy() - expect(within(changelogDecisionGuideSection as HTMLElement).getByText('Need notices, corresponding source, or release follow-through?')).toBeTruthy() + expect(within(changelogDecisionGuideSection as HTMLElement).getByText('Need legal details, release notes, or source links?')).toBeTruthy() expect(within(changelogDecisionGuideSection as HTMLElement).getByRole('link', { name: 'Review public notices' }).getAttribute('href')).toBe('/open-source-notices') expect(screen.getByText('Release rollout checklist')).toBeTruthy() expect(screen.getByText('Read the actual lane that changed')).toBeTruthy() @@ -2050,10 +2050,10 @@ describe('public marketing pages', () => { expect((await within(noticesView.container).findAllByRole('link', { name: 'https://hypertwist.app/open-source/source.zip' })).length).toBeGreaterThan(0) expect((await within(noticesView.container).findAllByRole('link', { name: 'https://github.com/hypertwist/hypertwist' })).length).toBeGreaterThan(0) expect(within(noticesView.container).getByText('Choose the right HyperTwist surface')).toBeTruthy() - expect(within(noticesView.container).getByText('Choose the next release move')).toBeTruthy() - expect(within(noticesView.container).getByText('Need notices, corresponding source, or release follow-through?')).toBeTruthy() - expect(within(noticesView.container).getByText('Current surface authority map')).toBeTruthy() - expect(within(noticesView.container).getByText('Offline operator manual')).toBeTruthy() + expect(within(noticesView.container).getByText('Choose the next best step')).toBeTruthy() + expect(within(noticesView.container).getByText('Need legal details, release notes, or source links?')).toBeTruthy() + expect(within(noticesView.container).getByText('Where each part of HyperTwist lives')).toBeTruthy() + expect(within(noticesView.container).getAllByText('Offline desktop guide').length).toBeGreaterThan(0) expect(within(noticesView.container).getByText('Current packaged desktop proof')).toBeTruthy() expect(within(noticesView.container).getByText('Packaged validation passed')).toBeTruthy() @@ -2061,10 +2061,10 @@ describe('public marketing pages', () => { expect(within(privacyView.container).getByText('Practical privacy boundary')).toBeTruthy() expect(within(privacyView.container).getByText('Browser identity and billing boundary')).toBeTruthy() expect(within(privacyView.container).getByText('Choose the right HyperTwist surface')).toBeTruthy() - expect(within(privacyView.container).getByText('Choose the next release move')).toBeTruthy() - expect(within(privacyView.container).getByText('Need account state, pairing, or protected browser follow-through?')).toBeTruthy() + expect(within(privacyView.container).getByText('Choose the next best step')).toBeTruthy() + expect(within(privacyView.container).getByText('Need account access, pairing, or dashboard help?')).toBeTruthy() expect(within(privacyView.container).getByText('Browser and desktop responsibilities')).toBeTruthy() - expect(within(privacyView.container).getByText('Current surface authority map')).toBeTruthy() + expect(within(privacyView.container).getByText('Where each part of HyperTwist lives')).toBeTruthy() expect(within(privacyView.container).getByText('Support-safe escalation boundary')).toBeTruthy() expect(within(privacyView.container).getByText('Current packaged desktop proof')).toBeTruthy() expect(within(privacyView.container).getByText('Packaged validation passed')).toBeTruthy() @@ -2075,10 +2075,10 @@ describe('public marketing pages', () => { expect(within(termsView.container).getByText('Terms in practice')).toBeTruthy() expect(within(termsView.container).getByText('Access model')).toBeTruthy() expect(within(termsView.container).getByText('Choose the right HyperTwist surface')).toBeTruthy() - expect(within(termsView.container).getByText('Choose the next release move')).toBeTruthy() - expect(within(termsView.container).getByText('Need the protected desktop-download lane?')).toBeTruthy() + expect(within(termsView.container).getByText('Choose the next best step')).toBeTruthy() + expect(within(termsView.container).getByText('Need the desktop download?')).toBeTruthy() expect(within(termsView.container).getByText('Browser and desktop responsibilities')).toBeTruthy() - expect(within(termsView.container).getByText('Current surface authority map')).toBeTruthy() + expect(within(termsView.container).getByText('Where each part of HyperTwist lives')).toBeTruthy() expect(within(termsView.container).getByText('Release and redistribution checklist')).toBeTruthy() expect(within(termsView.container).getByText('Current packaged desktop proof')).toBeTruthy() expect(within(termsView.container).getByText('Packaged validation passed')).toBeTruthy() @@ -2087,15 +2087,15 @@ describe('public marketing pages', () => { const shippingPaymentView = renderWithProviders(, ['/shipping-payment']) expect(within(shippingPaymentView.container).getByText('Digital delivery workflow')).toBeTruthy() - expect(within(shippingPaymentView.container).getByText('Protected entitlement handoff')).toBeTruthy() + expect(within(shippingPaymentView.container).getByText('Private download handoff')).toBeTruthy() expect(within(shippingPaymentView.container).getByText('What happens after access is granted')).toBeTruthy() expect(within(shippingPaymentView.container).getByText('Choose the right HyperTwist surface')).toBeTruthy() - expect(within(shippingPaymentView.container).getByText('Choose the next release move')).toBeTruthy() - expect(within(shippingPaymentView.container).getByText('Need plan selection, billing, or operator provisioning?')).toBeTruthy() + expect(within(shippingPaymentView.container).getByText('Choose the next best step')).toBeTruthy() + expect(within(shippingPaymentView.container).getByText('Need pricing, billing, or subscription help?')).toBeTruthy() expect(within(shippingPaymentView.container).getByText('Release references and source availability')).toBeTruthy() expect(within(shippingPaymentView.container).getByRole('link', { name: 'https://notes.hypertwist.app' })).toBeTruthy() - expect(within(shippingPaymentView.container).getByText('Current surface authority map')).toBeTruthy() - expect(within(shippingPaymentView.container).getByText('Offline operator manual')).toBeTruthy() + expect(within(shippingPaymentView.container).getByText('Where each part of HyperTwist lives')).toBeTruthy() + expect(within(shippingPaymentView.container).getAllByText('Offline desktop guide').length).toBeGreaterThan(0) expect(within(shippingPaymentView.container).getByText('Terms of access in practice')).toBeTruthy() expect(within(shippingPaymentView.container).getByText('Distribution doctrine')).toBeTruthy() expect(within(shippingPaymentView.container).getByText('Release and redistribution checklist')).toBeTruthy() diff --git a/website/src/__tests__/route-shells.test.tsx b/website/src/__tests__/route-shells.test.tsx index 241a5bd..d8ca771 100644 --- a/website/src/__tests__/route-shells.test.tsx +++ b/website/src/__tests__/route-shells.test.tsx @@ -158,9 +158,9 @@ describe('website route and shell behavior', () => { const { container } = renderProtectedRoute('/app/account') - expect(screen.getByText('Loading operator access...')).toBeTruthy() - expect(screen.getByText('Browser account access')).toBeTruthy() - expect(screen.getByText(/Checking your saved browser session, protected release status, and browser-to-desktop continuity/i)).toBeTruthy() + expect(screen.getByText('Loading your account...')).toBeTruthy() + expect(screen.getByText('Signed-in website access')).toBeTruthy() + expect(screen.getByText(/Checking your saved session, download access, and desktop pairing/i)).toBeTruthy() expect(container.querySelector('.general-page-loader-shell--fullscreen')).not.toBeNull() expect(screen.getByAltText('HyperTwist')).toBeTruthy() expect(screen.getByRole('link', { name: 'Open sign-in' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Faccount') diff --git a/website/src/auth/auth-shell-backdrop.ts b/website/src/auth/auth-shell-backdrop.ts index 4d65c4c..14a195e 100644 --- a/website/src/auth/auth-shell-backdrop.ts +++ b/website/src/auth/auth-shell-backdrop.ts @@ -9,7 +9,7 @@ function applyAuthShellBackdropStyles(backdrop: HTMLElement) { backdrop.style.zIndex = '0' backdrop.style.pointerEvents = 'none' backdrop.style.background = - 'radial-gradient(circle at top, rgba(216,203,175,0.12), transparent 40%), linear-gradient(180deg, rgba(18,20,24,0.97), rgba(10,12,17,0.99))' + 'radial-gradient(circle at top, rgba(84,203,255,0.12), transparent 32%), radial-gradient(circle at 82% 14%, rgba(247,178,103,0.12), transparent 24%), linear-gradient(180deg, rgba(9,12,24,0.26), rgba(7,10,19,0.38))' } export function isAuthShellRoute(pathname: string) { diff --git a/website/src/components/layout/MarketingShell.tsx b/website/src/components/layout/MarketingShell.tsx index 87a0b49..50c421e 100644 --- a/website/src/components/layout/MarketingShell.tsx +++ b/website/src/components/layout/MarketingShell.tsx @@ -10,24 +10,24 @@ import { HyperTwistButton, HyperTwistButtonLink } from '../ui/HyperTwistButton' export const publicProductRealityStrip = (
-

Primary product

- Desktop simulator -

Native Unreal owns the real training runtime, package proof, and higher-dimensional execution.

+

Main experience

+ Desktop app +

Daily training, replay review, coaching, and the deepest puzzle families all live in the desktop app.

-

Web purpose

- Access and guidance -

The browser owns docs, accounts, pricing, notices, protected downloads, and desktop pairing.

+

Website role

+ Account and launch hub +

Create your account, compare plans, read updates, get help, and unlock desktop downloads from the website.

-

Ready today

+

Ready now

Keyboard and mouse -

Desktop controls support serious keyboard, mouse, touch, camera, replay, and training work without a headset.

+

Train and explore with keyboard and mouse today, while broader headset support stays clearly marked as still in validation.

-

Account delivery

- Account-gated delivery -

Public pages explain the product; signed-in dashboard routes handle release access and pairing.

+

Download path

+ Account-backed delivery +

Start on the site, sign in once, and carry your account cleanly into the desktop build for access and first-launch pairing.

) @@ -38,30 +38,30 @@ export const compactProductRealityStrip = ( aria-label="Current HyperTwist product reality" >
-

Primary product

- Desktop simulator -

Native Unreal owns the real training runtime, package proof, and higher-dimensional execution.

+

Main experience

+ Desktop app +

Daily training, replay review, coaching, and the deepest puzzle families all live in the desktop app.

-

Web purpose

- Access and guidance -

The browser owns docs, accounts, pricing, notices, protected downloads, and desktop pairing.

+

Website role

+ Account and launch hub +

Create your account, compare plans, read updates, get help, and unlock desktop downloads from the website.

-

Ready today

+

Ready now

Keyboard and mouse -

Desktop controls support serious keyboard, mouse, touch, camera, replay, and training work without a headset.

+

Train and explore with keyboard and mouse today, while broader headset support stays clearly marked as still in validation.

-

Account delivery

- Account-gated delivery -

Public pages explain the product; signed-in dashboard routes handle release access and pairing.

+

Download path

+ Account-backed delivery +

Start on the site, sign in once, and carry your account cleanly into the desktop build for access and first-launch pairing.

) function useHideHeaderOnScroll() { - const [hidden, setHidden] = useState(false) + const [hidden, setHidden] = useState(() => (typeof window !== 'undefined' ? window.scrollY > 220 : false)) useEffect(() => { let previousScrollY = window.scrollY @@ -69,12 +69,13 @@ function useHideHeaderOnScroll() { function updateHeaderVisibility() { const nextScrollY = window.scrollY - const isScrollingDown = nextScrollY > previousScrollY + 8 - const isScrollingUp = nextScrollY < previousScrollY - 8 + const delta = nextScrollY - previousScrollY + const isScrollingDown = delta > 12 + const isNearTop = nextScrollY < 172 - if (nextScrollY < 96 || isScrollingUp) { + if (isNearTop) { setHidden(false) - } else if (isScrollingDown && nextScrollY > 160) { + } else if (isScrollingDown && nextScrollY > 220) { setHidden(true) } @@ -158,14 +159,23 @@ export function MarketingShell({ onClick={toggleColorMode} className="theme-toggle" > - {colorMode === 'dark' ? : } - {colorMode === 'dark' ? 'Light' : 'Dark'} + + + {colorMode === 'dark' ? : } + + {colorMode === 'dark' ? 'Light' : 'Dark'} + + {!isAuthenticated ? ( + + Create account + + ) : null} {isAuthenticated ? 'Open dashboard' : 'Log in'} - Get desktop app + Get the desktop app @@ -190,11 +200,16 @@ export function MarketingShell({

- Get desktop app + Get the desktop app - {isAuthenticated ? 'Account dashboard' : 'Account access'} + {isAuthenticated ? 'Account overview' : 'Account sign-in'} + {!isAuthenticated ? ( + + Start free account + + ) : null}
@@ -215,7 +230,7 @@ export function MarketingShell({ ))}

- Public distribution surfaces must continue to expose open-source notices and corresponding-source guidance when shipped builds contain MPL-covered material. + Downloadable releases include open-source notices and corresponding-source links whenever the shipped build requires them.

diff --git a/website/src/components/routes/ProtectedRoute.tsx b/website/src/components/routes/ProtectedRoute.tsx index b1825e8..11adf81 100644 --- a/website/src/components/routes/ProtectedRoute.tsx +++ b/website/src/components/routes/ProtectedRoute.tsx @@ -13,9 +13,9 @@ export function ProtectedRoute() { if (isLoading) { return ( diff --git a/website/src/components/seo/SiteMetadata.tsx b/website/src/components/seo/SiteMetadata.tsx index f7d9fed..2c2683a 100644 --- a/website/src/components/seo/SiteMetadata.tsx +++ b/website/src/components/seo/SiteMetadata.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react' import { brandConfig } from '../../site-config' const DEFAULT_DESCRIPTION = - 'HyperTwist is a native cube and hypercube training environment for recognition, replay, coaching, higher-dimensional runtime ownership, and desktop-first operator workflows.' + 'HyperTwist is the desktop-first cube and hypercube simulator for guided practice, replay review, coaching, and serious 120‑cell and 5D study.' const DEFAULT_IMAGE_PATH = '/branding/hypertwist-3d-symbol.png' function ensureMetaTag(attributeName: 'name' | 'property', attributeValue: string) { diff --git a/website/src/components/ui/BrowserAuthMethodsGuide.tsx b/website/src/components/ui/BrowserAuthMethodsGuide.tsx index 1a98498..f734469 100644 --- a/website/src/components/ui/BrowserAuthMethodsGuide.tsx +++ b/website/src/components/ui/BrowserAuthMethodsGuide.tsx @@ -4,6 +4,7 @@ import { isGoogleOAuthEnabled, isOrcidOAuthEnabled, } from '../../auth/supertokens-runtime' +import { HyperTwistButtonLink } from './HyperTwistButton' type BrowserAuthMethodCard = { title: string @@ -16,11 +17,11 @@ function buildBrowserAuthMethodCards(): readonly BrowserAuthMethodCard[] { { title: 'Email and password', description: - 'This is the default browser-account lane and remains the most predictable shared-auth path across early access, mixed, and production deployments.', + 'This is the simplest way to create your HyperTwist account and unlock the dashboard, downloads, and desktop pairing tools.', bullets: [ - 'Use it when you want the clearest route into the protected dashboard, protected downloads, and desktop-link pairing.', - 'It opens the same protected account and release surfaces as the optional provider buttons.', - 'It does not change the desktop-first simulator boundary or replace native pairing.', + 'Use it when you want the clearest route into your account, downloads, and first desktop launch.', + 'It opens the same dashboard and download tools as the optional provider buttons.', + 'It helps you reach the simulator; it does not replace the desktop app itself.', ], }, ] @@ -29,10 +30,10 @@ function buildBrowserAuthMethodCards(): readonly BrowserAuthMethodCard[] { cards.push({ title: 'GitHub sign-in', description: - 'GitHub is available in this build as an optional browser-account shortcut when the shared auth server has that provider configured.', + 'GitHub can be used as a faster sign-in route when this deployment has it enabled.', bullets: [ - 'Use it to enter the same protected dashboard and release lanes without creating a separate password first.', - 'It still relies on the same shared auth runtime, entitlement checks, and desktop-link handoff as the email/password lane.', + 'You still land in the same dashboard, downloads, and pairing tools.', + 'It uses the same account and entitlement checks as email and password.', ], }) } @@ -41,10 +42,10 @@ function buildBrowserAuthMethodCards(): readonly BrowserAuthMethodCard[] { cards.push({ title: 'Google sign-in', description: - 'Google is available in this build as an optional shared-auth provider for browser account continuity.', + 'Google can be used for the same account and download flow when it is enabled on this deployment.', bullets: [ - 'Use it when you want the same protected download, account, and rollout surfaces through a Google-backed sign-in flow.', - 'It does not widen browser ownership into simulator execution or change the desktop pairing boundary.', + 'It opens the same dashboard, downloads, and account tools as the default sign-in.', + 'It does not change the boundary between the website and the desktop simulator.', ], }) } @@ -53,10 +54,10 @@ function buildBrowserAuthMethodCards(): readonly BrowserAuthMethodCard[] { cards.push({ title: 'ORCID sign-in', description: - 'ORCID is available in this build as a first-party shared-auth provider, so research-oriented identity can route through the same protected operator lanes.', + 'ORCID can be used here when research-oriented identity needs to flow into the same HyperTwist account experience.', bullets: [ - 'Use it when this deployment has ORCID configured and you want standards-backed browser sign-in continuity into the protected dashboard and download lanes.', - 'It remains a browser-account path only; it does not replace desktop-link pairing or the native simulator runtime.', + 'It opens the same dashboard and download tools when the deployment has ORCID configured.', + 'It remains an account-access path only; the desktop simulator still does the training work.', ], }) } @@ -79,10 +80,10 @@ export function BrowserAuthMethodsGuide() { const summary = authRuntimeValidation.ready ? ( diagnostics.length === 0 - ? 'The shared browser-auth runtime is configured cleanly in this build, so the methods below all route into the same protected account, release, and desktop-pairing surfaces.' - : 'The shared browser-auth runtime is present in this build, but remaining warnings should be cleared before this surface is treated as fully production-ready.' + ? 'The sign-in options below all lead into the same HyperTwist account, download, and desktop-pairing experience.' + : 'The sign-in options are available, but a few configuration warnings still remain in this deployment.' ) - : 'This build may still rely on bounded recovery mode until the pending shared-auth runtime values are configured, even though the method lineup below stays useful as operator guidance.' + : 'This deployment may still be running with a limited auth configuration, but the sign-in lineup below remains the intended account path.' return (
@@ -112,6 +113,14 @@ export function BrowserAuthMethodsGuide() { ))}
+
+ + Create account + + + Log in + +
) } diff --git a/website/src/components/ui/HyperTwistButton.tsx b/website/src/components/ui/HyperTwistButton.tsx index 92021e4..4142392 100644 --- a/website/src/components/ui/HyperTwistButton.tsx +++ b/website/src/components/ui/HyperTwistButton.tsx @@ -22,7 +22,6 @@ function buildClassName({ return [ 'button', `button--${tone}`, - tone === 'secondary' ? 'button--primary' : '', full ? 'button--full' : '', className || '', ].filter(Boolean).join(' ') diff --git a/website/src/pages/auth-pages.tsx b/website/src/pages/auth-pages.tsx index 1f4a87e..0b4a712 100644 --- a/website/src/pages/auth-pages.tsx +++ b/website/src/pages/auth-pages.tsx @@ -12,7 +12,7 @@ import { } from '../auth/supertokens-runtime' import { SiteMetadata } from '../components/seo/SiteMetadata' import { compactProductRealityStrip } from '../components/layout/MarketingShell' -import { HyperTwistButton } from '../components/ui/HyperTwistButton' +import { HyperTwistButton, HyperTwistButtonLink } from '../components/ui/HyperTwistButton' import { OperationalStatusCallout } from '../components/ui/OperationalStatusCallout' import { browserDesktopRealityCards, deliverySurfaceCards, desktopWorkflowTracks, operatorManualTracks } from '../site-data' import { buildSupportPath, getDownloadPlatformLabel, normalizeDownloadPlatform } from '../site-routes' @@ -62,50 +62,50 @@ function resolveAuthNextStep(nextPath: string): AuthNextStepDescriptor { const platformLabel = platform ? getDownloadPlatformLabel(platform) : 'desktop' return { - title: `Protected ${platformLabel} release lane`, + title: `Signed-in ${platformLabel} downloads`, description: - `After sign-in you will continue to the protected ${platformLabel} download center so entitlement, current package proof, and release-notice follow-through stay tied to your account instead of being exposed on an anonymous page.`, + `After sign-in you will continue to the signed-in ${platformLabel} download center so entitlement, current package proof, and release notes stay tied to your account instead of being exposed on an anonymous page.`, bullets: [ `Review the current ${platformLabel} target, package proof, and release notes before download.`, - 'Use the protected dashboard afterward if you need a desktop-link token for first launch.', - 'Return to protected or public notices if rollout or compliance status changes.', + 'Use the dashboard afterward if you need a desktop-link token for first launch.', + 'Return to notices if rollout or compliance status changes.', ], } } if (pathname === '/app/account') { return { - title: 'Protected account lane', + title: 'Signed-in account', description: - 'After sign-in you will continue to the protected account surface so session state, plan status, and browser-to-desktop access continuity can be confirmed before any download or rollout step.', + 'After sign-in you will continue to your account page so session state, plan status, and desktop access continuity can be confirmed before any download or rollout step.', bullets: [ 'Confirm your plan, role, and current release access first.', - 'Use the protected download center once desktop entitlement is resolved.', - 'Use the dashboard and notices lanes if account or release status changes later.', + 'Use the signed-in download center once desktop entitlement is resolved.', + 'Use the dashboard and notices pages if account or release status changes later.', ], } } if (pathname === '/app/notices') { return { - title: 'Protected notices lane', + title: 'Signed-in notices', description: - 'After sign-in you will continue to the protected notices surface so distribution references, corresponding-source status, and release-target notice truth remain attached to the signed-in operator lane.', + 'After sign-in you will continue to the signed-in notices page so distribution references, source status, and release details remain attached to your account.', bullets: [ 'Review notices before redistributing any covered downloadable build.', - 'Use the protected download center when you need the entitled package itself.', - 'Keep browser access, native package proof, and legal follow-through synchronized.', + 'Use the signed-in download center when you need the entitled package itself.', + 'Keep account access, native package proof, and legal follow-through synchronized.', ], } } return { - title: 'Protected operator dashboard', + title: 'Signed-in dashboard', description: - 'After sign-in you will continue to the protected operator dashboard so browser auth, billing, release status, and desktop-link pairing are resolved before the native simulator lane takes over.', + 'After sign-in you will continue to the signed-in dashboard so browser auth, billing, release status, and desktop-link pairing are resolved before the native simulator takes over.', bullets: [ 'Confirm account, plan, and release readiness first.', - 'Open the protected download center when you need the entitled desktop build.', + 'Open the signed-in download center when you need the entitled desktop build.', 'Generate a desktop-link token there or from the dashboard before first native launch.', ], } @@ -129,8 +129,8 @@ function AuthNextStepNotice({ nextPath }: { nextPath: string }) { function AuthAccessGuide({ nextPath }: { nextPath: string }) { const nextStep = resolveAuthNextStep(nextPath) - const dashboardCard = deliverySurfaceCards.find((card) => card.title === 'Protected browser dashboard') - const runtimeCard = deliverySurfaceCards.find((card) => card.title === 'Native Unreal desktop runtime') + const dashboardCard = deliverySurfaceCards.find((card) => card.title === 'Signed-in dashboard') + const runtimeCard = deliverySurfaceCards.find((card) => card.title === 'Desktop simulator') const pairingTrack = operatorManualTracks.find((track) => track.title === '3. Pair the installed desktop runtime') return ( @@ -242,21 +242,21 @@ function AuthRuntimeNotice() { } summary={ authRuntimeValidation.ready - ? 'You can still sign in, create an account, and continue into protected dashboard routes. Operator diagnostics keep the deeper auth warnings visible after sign-in.' - : 'If shared auth is temporarily unavailable, HyperTwist keeps account routing recoverable so you can still review product access and support paths.' + ? 'You can still sign in, create an account, and continue into your dashboard, downloads, and desktop pairing flow.' + : 'If shared auth is temporarily unavailable, HyperTwist still keeps account routing recoverable so you can review access, downloads, and support paths.' } sections={[ { title: 'What still works', items: [ 'Login, registration, and safe next-step routing remain available.', - 'The protected dashboard can still recover bounded account, release, and desktop-pairing status after sign-in.', + 'The dashboard can still recover your account, release, and desktop-pairing status after sign-in.', ], }, { - title: 'What stays intentionally bounded', + title: 'What may still need follow-through', items: [ - 'Shared production auth, live entitlement authority, and deployment-grade session guarantees are not claimed until this auth surface is fully green.', + 'Some shared-auth or billing details may still need finishing work before this deployment is fully launch-ready.', ], }, { @@ -264,11 +264,11 @@ function AuthRuntimeNotice() { items: diagnostics, }, { - title: 'Recommended recovery order', + title: 'Best next step', items: [ authRuntimeValidation.ready - ? 'Continue into the dashboard for account-aware status, downloads, and desktop-link pairing.' - : 'Use account creation for orientation now; contact support if you need production release access immediately.', + ? 'Continue into the dashboard for account status, downloads, and desktop pairing.' + : 'Create an account for orientation now, then contact support if you need release access immediately.', ], }, ]} @@ -337,7 +337,7 @@ export function LoginPage() { /> Need access? Create an account.

} > @@ -377,6 +377,14 @@ export function LoginPage() { {isSubmitting ? 'Signing in...' : 'Log in'} +
+ + Create account + + + Learn how the website and desktop app work together + +
{isGoogleOAuthEnabled() ? ( @@ -461,7 +469,7 @@ export function RegisterPage() { /> Already have access? Log in.

} > @@ -513,6 +521,14 @@ export function RegisterPage() { {isSubmitting ? 'Creating account...' : 'Create account'} +
+ + Already have an account? Log in + + + Compare plans first + +
{isGoogleOAuthEnabled() ? ( diff --git a/website/src/pages/public-page-helpers.tsx b/website/src/pages/public-page-helpers.tsx index 7dc029b..a5744aa 100644 --- a/website/src/pages/public-page-helpers.tsx +++ b/website/src/pages/public-page-helpers.tsx @@ -52,61 +52,61 @@ export const supportTopicGuidance: Record = { 'launch-readiness': { title: 'Launch readiness', description: - 'Need help turning early access into a public launch? We can walk through checkout wiring, download release targets, notices, and corresponding-source publication.', + 'Use this path when you need the current website, pricing, download, and legal status before a wider public launch.', steps: [ - 'Confirm public launch status, operator/studio checkout status, and support contact first.', - 'Review the current desktop target plus packaged proof before promising a release lane externally.', - 'Keep notices and corresponding-source status live before widening rollout.', + 'Confirm public launch status, checkout readiness, and support contact first.', + 'Review the current desktop target plus packaged proof before promising a release externally.', + 'Keep notices and corresponding-source links visible before a wider launch.', ], routeFocus: [ 'Launch-status, pricing, and download pages explain public launch status and target selection.', - 'Public notices and terms pages carry the distribution and legal follow-through.', - 'The public manual explains the browser-versus-desktop product split that launch copy must preserve.', + 'Public notices and terms pages carry the distribution and legal details.', + 'The public manual explains how the website and desktop app work together so launch messaging stays accurate.', ], actions: [ { label: 'Open launch status', to: '/launch-status' }, - { label: 'Sign in for protected release lane', to: buildLoginPath(buildProtectedDownloadPath('windows')) }, - { label: 'Sign in for protected notices', to: buildLoginPath('/app/notices') }, + { label: 'Sign in for desktop downloads', to: buildLoginPath(buildProtectedDownloadPath('windows')) }, + { label: 'Sign in for notices', to: buildLoginPath('/app/notices') }, { label: 'Open pricing', to: '/pricing' }, ], }, 'operator-access': { - title: 'Operator access', + title: 'Account access', description: - 'Use this lane when you need operator checkout, entitlement enablement, or help reaching the protected desktop-download surface.', + 'Use this path when you need sign-up help, account approval, subscription access, or the signed-in desktop download.', steps: [ - 'Start with sign-in or registration, then confirm whether the issue is auth, entitlement, or desktop-link pairing.', - 'Use the protected dashboard and protected download lane once sign-in succeeds so account and release status stay attached.', + 'Start with sign-in or signup, then confirm whether the issue is account access, entitlement, or desktop pairing.', + 'Use the signed-in dashboard and download center once sign-in succeeds so your account and release status stay attached.', 'Escalate with the affected plan, requested platform, and whether access, pairing, or package delivery failed.', ], routeFocus: [ - 'Login and register preserve safe next-target routing into the protected operator lanes.', - 'The public download page shows release status without exposing raw delivery authority.', - 'The public manual explains when the browser dashboard owns the next step and when the native runtime takes over.', + 'Login and signup preserve your next destination so you land in the right dashboard or download view.', + 'The public download page shows release status without exposing raw delivery links.', + 'The public manual explains when the website owns the next step and when the desktop app takes over.', ], actions: [ - { label: 'Sign in for protected downloads', to: buildLoginPath(buildProtectedDownloadPath('windows')) }, + { label: 'Sign in for desktop downloads', to: buildLoginPath(buildProtectedDownloadPath('windows')) }, { label: 'Create account for desktop access', to: buildRegisterPath(buildProtectedDownloadPath('windows')) }, - { label: 'Open protected dashboard', to: buildLoginPath('/app') }, + { label: 'Open dashboard', to: buildLoginPath('/app') }, ], }, 'studio-rollout': { - title: 'Studio rollout', + title: 'Teams and studios', description: - 'Use this lane for higher-dimensional rollout planning, deployment coordination, or production-lane package and notice readiness.', + 'Use this path for studio, classroom, or team planning, especially when higher-dimensional training and release readiness need to be reviewed together.', steps: [ - 'Treat packaged proof, notices, pricing, and delivery status as one rollout packet instead of four disconnected checks.', - 'Keep browser/operator coordination separate from native simulator execution during deployment planning.', - 'Carry higher-dimensional dedicated-family proof and the current XR/controller boundary into rollout decisions explicitly.', + 'Review packaged proof, notices, pricing, and delivery status together instead of as separate disconnected checks.', + 'Keep planning and account coordination separate from the simulator itself.', + 'Carry higher-dimensional readiness and the current XR/controller boundary into team decisions explicitly.', ], routeFocus: [ - 'Release notes and the public manual explain recent browser, package, and control-boundary changes.', + 'Release notes and the public manual explain recent website, desktop, and controls changes.', 'Download and notices pages carry the current distribution status plus legal follow-through.', - 'Resources summarize higher-dimensional runtime lanes and operator playbooks for wider team review.', + 'Resources summarize higher-dimensional training paths and team playbooks for wider review.', ], actions: [ - { label: 'Sign in for protected notices', to: buildLoginPath('/app/notices') }, - { label: 'Sign in for protected browser access', to: buildLoginPath('/app/browser-access') }, + { label: 'Sign in for notices', to: buildLoginPath('/app/notices') }, + { label: 'Sign in for browser access', to: buildLoginPath('/app/browser-access') }, { label: 'Open release notes', to: '/changelog' }, { label: 'Open resources', to: '/resources' }, ], @@ -239,8 +239,8 @@ export function DeliverySurfaceResponsibilitiesGrid({ limit }: { limit?: number } export function BrowserDesktopRealitySection({ - title = 'Why HyperTwist keeps both a website and a desktop runtime', - description = 'The browser shell is intentionally narrower than the simulator. That is what keeps access, release, billing, notices, and native execution from collapsing into one confused surface.', + title = 'Why HyperTwist gives you both a website and a desktop app', + description = 'The website gets you in, keeps your account and downloads organized, and handles plans, updates, and help. The desktop app is where the full simulator experience lives.', }: { title?: string description?: string @@ -272,12 +272,12 @@ export function BrowserDesktopRealitySection({ const surfaceChoiceGuideCards = [ { - title: 'Stay on the public website', - posture: 'Public release shell', - description: 'Use this surface when you are still evaluating HyperTwist, reading docs, checking access status, or reviewing pricing, notices, and rollout guidance.', + title: 'Stay on the website', + posture: 'Public website', + description: 'Use this when you are still exploring HyperTwist, reading the manual, comparing plans, or checking release status.', bullets: [ - 'Best for product discovery, public documentation, pricing, support, and legal follow-through.', - 'Keeps launch-readiness and packaged proof visible without exposing protected download authority.', + 'Best for product discovery, documentation, pricing, support, and release updates.', + 'Keeps launch details visible without exposing protected downloads on anonymous pages.', ], action: { to: '/docs', @@ -285,25 +285,25 @@ const surfaceChoiceGuideCards = [ }, }, { - title: 'Move into the protected dashboard', - posture: 'Signed-in operator shell', - description: 'Use this surface when identity, entitlement, billing, protected notices, or browser-to-desktop pairing starts to matter.', + title: 'Open your account dashboard', + posture: 'Signed-in dashboard', + description: 'Use this when your identity, plan, downloads, billing status, or desktop pairing starts to matter.', bullets: [ - 'Best for account state, protected downloads, desktop-link pairing, and release-manifest viewer truth.', - 'Keeps the operator inside direct signed-in routes instead of routing them back through anonymous guidance.', + 'Best for account state, protected downloads, desktop-link pairing, and release updates tied to your plan.', + 'Keeps you inside signed-in routes instead of bouncing you back through anonymous guidance.', ], action: { to: '/app', - label: 'Open operator dashboard', + label: 'Open dashboard', }, }, { - title: 'Use the desktop runtime', - posture: 'Simulator authority', - description: 'Use this surface when you need the actual training loop, packaged higher-dimensional maps, replay/coaching behavior, or simulator-side diagnostics.', + title: 'Launch the desktop app', + posture: 'Desktop simulator', + description: 'Use this when you want the actual training loop, replay review, higher-dimensional maps, or the full simulator experience.', bullets: [ - 'Best for classic-cube execution, dedicated-family Magic120Cell and MagicCube5D work, and packaged validation truth.', - 'Owns the real simulator behavior that the public and protected browser surfaces intentionally do not claim.', + 'Best for classic-cube execution, dedicated 120‑cell and 5D sessions, and the strongest training fidelity.', + 'This is the real simulator experience that the website intentionally does not pretend to replace.', ], action: { to: '/download', @@ -346,7 +346,7 @@ export function SurfaceChoiceGuideSection({ export function OperatorDesktopQuickstartSection({ title = 'First real desktop session', - description = 'This is the shortest honest path from browser discovery into the native simulator: resolve access, pair the installed runtime safely, verify the first training lane, and keep the current XR/controller boundary visible.', + description = 'This is the shortest path from website discovery into the real simulator: create your account, pair your install, verify the first session, and know exactly what is ready today.', }: { title?: string description?: string @@ -371,7 +371,7 @@ export function OperatorDesktopQuickstartSection({ Open download center - Open operator dashboard + Open dashboard Open public manual @@ -382,8 +382,8 @@ export function OperatorDesktopQuickstartSection({ } export function DownloadableOperatorManualSection({ - title = 'Offline operator manual', - description = 'HyperTwist now ships a same-origin downloadable operator manual so the desktop-first onboarding, control-boundary truth, and rollout guidance can travel with the product instead of living only in live browser routes.', + title = 'Offline desktop guide', + description = 'HyperTwist ships a downloadable guide so onboarding, controls, advanced puzzle guidance, and release notes can travel with the app instead of living only on the website.', }: { title?: string description?: string @@ -392,18 +392,18 @@ export function DownloadableOperatorManualSection({

- The downloadable manual bundles the current first-session path, browser-versus-desktop - boundary, protected dashboard follow-through, control roster, higher-dimensional runtime - guide, and the current XR/controller truth into one offline reference. + The downloadable guide bundles the first-session path, the website-versus-desktop split, + signed-in access, controls, higher-dimensional guidance, and the current + XR/controller status into one offline reference.

    -
  • Use it for desktop-side onboarding, rollout review, and operator support when the browser shell is not the best reading surface.
  • -
  • It stays aligned with the current public route atlas instead of inventing a separate product story.
  • -
  • It keeps the current headset/controller validation boundary explicit instead of flattening it into generic VR support language.
  • +
  • Use it for desktop-side onboarding, launch review, and support when the website is not the best reading surface.
  • +
  • It stays aligned with the public manual instead of inventing a separate product story.
  • +
  • It keeps the current headset and controller status explicit instead of flattening it into vague VR claims.
- Download offline operator manual + Download offline desktop guide Open public manual @@ -442,7 +442,7 @@ export function PrincipleCardSection({ export function SimulatorManualSection({ title = 'Simulator manual', - description = 'These are the current product-safe usage tracks for the native runtime itself.', + description = 'These are the current usage tracks for the desktop app itself.', }: { title?: string description?: string @@ -452,7 +452,7 @@ export function SimulatorManualSection({ export function HigherDimensionalRuntimeGuideSection({ title = 'Higher-dimensional family guide', - description = 'These are the currently represented higher-dimensional lanes and the truthful host/runtime model for each.', + description = 'These are the higher-dimensional puzzle families already represented in HyperTwist and where each one actually lives today.', }: { title?: string description?: string @@ -468,7 +468,7 @@ export function HigherDimensionalRuntimeGuideSection({ export function InputAndDevicePostureSection({ title = 'Input and device state', - description = 'Public documentation should be explicit about the current control/runtime truth instead of blurring groundwork and finished VR claims together.', + description = 'Public documentation should be explicit about the controls, devices, and current VR status instead of blurring groundwork and finished claims together.', }: { title?: string description?: string @@ -484,7 +484,7 @@ export function InputAndDevicePostureSection({ export function ControlProfileRosterSection({ title = 'Selectable control and settings roster', - description = 'This manual section answers the concrete user question: what settings, profiles, selectors, and persistence surfaces are already real today?', + description = 'This answers the practical user question: which settings, profiles, selectors, and saved preferences are already real today?', }: { title?: string description?: string @@ -500,7 +500,7 @@ export function ControlProfileRosterSection({ export function RuntimeControlGuideSection({ title = 'Runtime control guide', - description = 'This manual section explains how to approach the current desktop runtime without pretending the currently closed XR/controller branch has already been reopened.', + description = 'This manual section explains how to use the current desktop app without pretending the unfinished XR/controller branch is already complete.', }: { title?: string description?: string @@ -622,7 +622,7 @@ export function FaqCardSection({ export function BrowserDesktopDecisionFaqSection({ title = 'Common browser-versus-desktop questions', - description = 'These are the direct product-boundary answers most operators want before deciding whether the browser lane is enough on its own or whether they should move into the native runtime.', + description = 'These are the direct product-boundary answers most people want before deciding whether the website is enough on its own or whether they should move into the native runtime.', }: { title?: string description?: string @@ -658,7 +658,7 @@ export function SupportTopicDirectorySection({ key={topic.topicKey} className={`card${isSelected ? ' card--selected' : ''}`} > - {isSelected ?

Selected help lane

: null} + {isSelected ?

Selected help topic

: null}

{topic.title}

{topic.description}

Next steps

@@ -690,7 +690,7 @@ export function SupportTopicDirectorySection({ export function PublicManualRouteAtlasSection({ title = 'Public manual route atlas', - description = 'Each public page has a different job inside HyperTwist. This atlas keeps the route set readable as a real manual rather than a flat marketing shell.', + description = 'Each public page has a different job inside HyperTwist. This atlas keeps the route set readable as a real manual instead of a flat landing site.', cards = publicManualRouteAtlasCards, limit, }: { @@ -728,7 +728,7 @@ export function PublicManualRouteAtlasSection({ export function BrowserAuthMethodsSection({ title = 'Browser account access methods', - description = 'The public browser-account provider lineup should stay visible wherever operators are being asked to sign in, buy access, pair the desktop runtime, or recover access state.', + description = 'Keep the available sign-in options visible wherever people are being asked to create an account, buy access, pair the desktop app, or recover access.', }: { title?: string description?: string @@ -780,7 +780,7 @@ type ReleaseAuthorityReference = { export function ReleaseAuthorityBundleSection({ releaseManifest, title = 'Release references and source availability', - description = 'Treat public docs, release notes, corresponding source, notices repository, and operator contact as one launch bundle so distribution-critical pages do not fragment the release story.', + description = 'Keep docs, release notes, source links, notices, and support in one place so buyers and teams can always see the full delivery story.', }: { releaseManifest: ReturnType title?: string @@ -788,19 +788,19 @@ export function ReleaseAuthorityBundleSection({ }) { const references: readonly ReleaseAuthorityReference[] = [ { - title: 'Downloadable operator manual', + title: 'Offline desktop guide', description: - 'A same-origin offline manual ships with the website so desktop-first onboarding, protected-release follow-through, and rollout review do not depend on live browsing alone.', + 'A same-origin offline manual ships with the website so desktop-first onboarding, download help, and launch review do not depend on live browsing alone.', href: downloadablePublicManualHref, configuredLabel: 'Included', - missingLabel: 'Add the downloadable operator manual before wider launch', - linkLabel: 'Download operator manual (.md)', + missingLabel: 'Add the offline desktop guide before wider launch', + linkLabel: 'Download offline desktop guide (.md)', download: true, }, { title: 'Public manual', description: - 'The public docs portal is the product-safe manual for browser-versus-desktop boundaries, rollout status, and simulator truth.', + 'The public docs portal is the main manual for browser-versus-desktop boundaries, launch status, and simulator truth.', href: releaseManifest.public_docs_url, configuredLabel: 'Configured', missingLabel: 'Add public docs URL before wider launch', @@ -828,16 +828,16 @@ export function ReleaseAuthorityBundleSection({ { title: 'Open-source repo and notices reference', description: - 'The public repository and notices reference keeps release, legal, and redistribution follow-through visible outside the simulator.', + 'The public repository and notices reference keeps release, legal, and redistribution details visible outside the simulator.', href: releaseManifest.open_source_repo_url, configuredLabel: 'Configured', missingLabel: 'Add public repo/notices URL before wider launch', linkLabel: releaseManifest.open_source_repo_url || 'Add public repo/notices URL before wider launch', }, { - title: 'Operator support contact', + title: 'Support contact', description: - 'Support contact belongs in the same bundle so release, entitlement, notice, and rollout questions do not force operators to improvise escalation paths.', + 'Support contact belongs in the same bundle so account, download, notice, and launch questions never need improvised escalation paths.', href: releaseManifest.support_email ? `mailto:${releaseManifest.support_email}` : null, configuredLabel: 'Ready', missingLabel: 'Add support email before wider launch', @@ -930,34 +930,34 @@ function buildPublicReleaseDecisionCards(releaseManifest: ReleaseManifestView): const releaseTargetCard: PublicReleaseDecisionCard = primaryTarget?.configured ? { badge: 'Desktop release target published', - title: 'Need the protected desktop-download lane?', + title: 'Need the desktop download?', summary: - 'The public site can confirm the current desktop release target, but actual package delivery still belongs to the signed-in protected release lane.', + 'The public site can confirm the current desktop release target, while the actual package still arrives through your signed-in download area.', bullets: [ `Current public target: ${describePublicReleaseTarget(primaryTarget)}`, `Configured release targets: ${configuredTargets.length}/${releaseManifest.platforms.length}`, primaryTarget.validation_summary - ? 'Public packaged proof is already attached to this lane.' - : 'This lane is published, but public packaged proof is not attached yet.', + ? 'Public package proof is already attached to this release.' + : 'This release is published, but public package proof is not attached yet.', ], actions: [ - { label: 'Sign in for protected downloads', to: buildLoginPath(buildProtectedDownloadPath('windows')) }, + { label: 'Sign in for desktop downloads', to: buildLoginPath(buildProtectedDownloadPath('windows')) }, { label: 'Create account for desktop access', to: buildRegisterPath(buildProtectedDownloadPath('windows')) }, { label: 'Open download center', to: '/download' }, ], } : { badge: 'Package publication pending', - title: 'Need the protected desktop-download lane?', + title: 'Need the desktop download?', summary: - 'The public site can still explain the release lane, but direct package delivery belongs in protected follow-through until a published desktop target is active.', + 'The public site can still explain the release path, but direct package delivery stays inside the signed-in flow until a published desktop target is active.', bullets: [ `Configured release targets: ${configuredTargets.length}/${releaseManifest.platforms.length}`, - `Primary default lane: ${primaryTarget ? primaryTarget.platform : 'Windows desktop lane pending publication'}`, + `Primary default target: ${primaryTarget ? primaryTarget.platform : 'Windows desktop release pending publication'}`, `Support contact: ${supportEmail}`, ], actions: [ - { label: 'Sign in for protected downloads', to: buildLoginPath(buildProtectedDownloadPath('windows')) }, + { label: 'Sign in for desktop downloads', to: buildLoginPath(buildProtectedDownloadPath('windows')) }, { label: 'Open download center', to: '/download' }, { label: 'Open launch-readiness support', to: buildSupportPath('launch-readiness') }, ], @@ -966,56 +966,56 @@ function buildPublicReleaseDecisionCards(releaseManifest: ReleaseManifestView): const provisioningCard: PublicReleaseDecisionCard = checkoutConfigured ? { badge: 'Checkout or provisioning route ready', - title: 'Need plan selection, billing, or operator provisioning?', + title: 'Need pricing, billing, or subscription help?', summary: - 'The website is not a brochure-only surface here: pricing is the public handoff into plan selection, then the protected dashboard resolves entitlement, downloads, and operator follow-through.', + 'The website is where pricing starts. After that, the signed-in dashboard resolves plan access, downloads, and account follow-through.', bullets: [ - `Operator checkout: ${releaseCommerce.operator_checkout_url ? 'configured' : 'manual help required'}`, - `Studio checkout: ${releaseCommerce.studio_checkout_url ? 'configured' : 'manual help required'}`, - 'Keep pricing on the public site, then move into the protected dashboard for account-aware release work.', + `Desktop plan checkout: ${releaseCommerce.operator_checkout_url ? 'configured' : 'manual help required'}`, + `Studio plan checkout: ${releaseCommerce.studio_checkout_url ? 'configured' : 'manual help required'}`, + 'Keep pricing on the public site, then move into the signed-in dashboard for account-aware release work.', ], actions: [ { label: 'Open pricing', to: '/pricing' }, - { label: 'Sign in for protected dashboard', to: buildLoginPath('/app') }, + { label: 'Sign in for dashboard', to: buildLoginPath('/app') }, ], } : { badge: 'Manual provisioning route', - title: 'Need plan selection, billing, or operator provisioning?', + title: 'Need pricing, billing, or subscription help?', summary: - 'Pricing can still explain the real delivery model, while account or support follow-through remains the truthful path until live checkout targets are active.', + 'Pricing can still explain the delivery model, while account or support follow-through remains the right path until live checkout targets are active.', bullets: [ - `Operator checkout: ${releaseCommerce.operator_checkout_url ? 'configured' : 'manual help required'}`, - `Studio checkout: ${releaseCommerce.studio_checkout_url ? 'configured' : 'manual help required'}`, + `Desktop plan checkout: ${releaseCommerce.operator_checkout_url ? 'configured' : 'manual help required'}`, + `Studio plan checkout: ${releaseCommerce.studio_checkout_url ? 'configured' : 'manual help required'}`, `Support contact: ${supportEmail}`, ], actions: [ { label: 'Open pricing', to: '/pricing' }, - { label: 'Open operator-access support', to: buildSupportPath('operator-access') }, + { label: 'Open access support', to: buildSupportPath('operator-access') }, ], } const browserContinuityCard: PublicReleaseDecisionCard = { - badge: 'Protected browser shell', - title: 'Need account state, pairing, or protected browser follow-through?', + badge: 'Signed-in website follow-through', + title: 'Need account access, pairing, or dashboard help?', summary: - 'The web lane is not superfluous: it owns identity, entitlement, billing status, protected notices, and browser-to-desktop pairing while the native runtime keeps simulator authority.', + 'The website handles your account, downloads, billing, legal details, and desktop pairing while the desktop app stays focused on training.', bullets: [ - 'Use the protected dashboard for account state, auth/runtime truth, and release-manifest follow-through.', - 'Use the protected browser-access lane when you need account-aware browser continuity rather than simulator execution.', - 'Move into the desktop runtime for the actual training loop, coaching, and higher-dimensional interaction.', + 'Use the signed-in dashboard for account status, release updates, and pairing follow-through.', + 'Use the signed-in browser-access route when you need account continuity rather than simulator execution.', + 'Move into the desktop app for the actual training loop, coaching, and higher-dimensional interaction.', ], actions: [ - { label: 'Sign in for protected dashboard', to: buildLoginPath('/app') }, - { label: 'Sign in for protected browser access', to: buildLoginPath('/app/browser-access') }, + { label: 'Sign in for dashboard', to: buildLoginPath('/app') }, + { label: 'Sign in for browser access', to: buildLoginPath('/app/browser-access') }, ], } const noticesCard: PublicReleaseDecisionCard = { badge: configuredReferenceCount === 5 ? 'Release references configured' : 'Some release references are still pending', - title: 'Need notices, corresponding source, or release follow-through?', + title: 'Need legal details, release notes, or source links?', summary: - 'Public notices and release references stay on the website first, while the protected notices lane remains the signed-in follow-through surface when account context matters.', + 'Public notices and release references stay on the website first, while the signed-in notices area helps when those details need to stay attached to your account.', bullets: [ `Configured public release references: ${configuredReferenceCount}/5`, 'Keep notices, release notes, and corresponding-source status visible anywhere downloadable distribution is discussed.', @@ -1024,7 +1024,7 @@ function buildPublicReleaseDecisionCards(releaseManifest: ReleaseManifestView): actions: [ { label: 'Review public notices', to: '/open-source-notices' }, { label: 'Review release notes', to: '/changelog' }, - { label: 'Sign in for protected notices', to: buildLoginPath('/app/notices') }, + { label: 'Sign in for notices', to: buildLoginPath('/app/notices') }, ], } @@ -1057,8 +1057,8 @@ function SurfaceActionLink({ export function PublicReleaseDecisionGuideSection({ releaseManifest, - title = 'Choose the next release move', - description = 'These cards keep the public pages practical: they show whether the next honest step is pricing, protected browser/account work, protected desktop access, or notices/source follow-through.', + title = 'Choose the next best step', + description = 'These cards keep the public pages practical: they show whether the next step is pricing, account access, the desktop download, or the release details around it.', }: { releaseManifest: ReleaseManifestView title?: string diff --git a/website/src/pages/public-pages-commerce.tsx b/website/src/pages/public-pages-commerce.tsx index b7bdc98..62ad003 100644 --- a/website/src/pages/public-pages-commerce.tsx +++ b/website/src/pages/public-pages-commerce.tsx @@ -80,13 +80,13 @@ export function PricingPage() { <>
@@ -107,8 +107,8 @@ export function PricingPage() {
@@ -126,16 +126,16 @@ export function PricingPage() { @@ -146,7 +146,7 @@ export function PricingPage() { @@ -157,7 +157,7 @@ export function PricingPage() { @@ -165,35 +165,35 @@ export function PricingPage() {

- Public pricing, checkout, and download pages are distribution surfaces. Before external launch, - keep their legal footer and open-source notices link live and ensure the corresponding-source URL is configured for any downloadable build containing MPL-covered material. + Public pricing, checkout, and download pages are part of the real product delivery story. That is why HyperTwist keeps release notes, + notices, and source links close to the buying path whenever a desktop build includes open-source obligations.

@@ -240,7 +240,7 @@ function ReleaseManifestStatusSections({ { title: 'What still works', items: [ - 'Supported targets, packaged proof, and public rollout guidance remain visible.', + 'Supported targets, packaged proof, and public release guidance remain visible.', 'Platform selection can still be preserved into the protected sign-in and download handoff.', ], }, @@ -254,8 +254,8 @@ function ReleaseManifestStatusSections({ { title: 'Recommended recovery order', items: [ - 'Use the protected dashboard once the auth server recovers if you need actual package delivery.', - 'Open operator support if release-authority recovery persists during rollout or purchase work.', + 'Use the signed-in dashboard once the auth server recovers if you need actual package delivery.', + 'Open support if release-authority recovery persists during purchase or release work.', ], }, ]} @@ -315,13 +315,13 @@ export function DownloadPage() { <>

Browser guide

-

Read why HyperTwist keeps the web version, what it does well, and where it is intentionally weaker than the downloadable.

+

Read what the web experience is for, what it does well, and where the desktop app goes deeper.

Help center

-

Open practical onboarding, controls, and rollout-safe troubleshooting guidance before or after the first install.

+

Open practical onboarding, controls, and troubleshooting guidance before or after the first install.

Contact

-

Open the human contact lane when the next move is support, rollout coordination, or pricing follow-through.

+

Open the human contact lane when the next move is support, team coordination, or pricing follow-through.

@@ -452,7 +452,7 @@ export function DownloadPage() {
@@ -460,11 +460,11 @@ export function DownloadPage() {

HyperTwist treats desktop distribution as an account-gated release surface. Public pages can describe supported targets and release status, but the actual - download links live behind the protected dashboard where plan and entitlement + download links live behind the signed-in dashboard where plan and entitlement state are resolved.

- Open protected download lane + Open protected download center
@@ -472,11 +472,11 @@ export function DownloadPage() {

- After sign-in, open the operator dashboard to generate a desktop-link token. + After sign-in, open the dashboard to generate a desktop-link token. That token is designed to hand browser identity and plan status over to the local desktop app without exposing your password.

- Open protected dashboard + Open dashboard
@@ -500,7 +500,7 @@ export function OpenSourceNoticesPage() {
@@ -549,27 +549,27 @@ export function OpenSourceNoticesPage() {
- +
@@ -604,7 +604,7 @@ export function OpenSourceNoticesPage() {
{releaseRolloutChecklist.map((card) => ( @@ -622,18 +622,18 @@ export function OpenSourceNoticesPage() {

- Contact {brandConfig.contact.email} when the next question is redistribution, corresponding-source follow-through, or release-surface notices rather than simulator behavior. + Contact {brandConfig.contact.email} when the next question is redistribution, corresponding source, or release-surface notices rather than simulator behavior.

@@ -663,13 +663,13 @@ export function PrivacyPage() {
  • The public website stores account/session data needed for authentication, plan access, and desktop-link issuance.
  • -
  • The browser shell does not claim ownership over the full simulator runtime state unless a future browser-client packet is explicitly opened.
  • +
  • The website does not claim ownership over the full simulator runtime state unless a future browser-client branch is explicitly opened.
  • Support, billing, and release operations should collect only the data required to deliver digital access and maintain legal compliance.
@@ -677,7 +677,7 @@ export function PrivacyPage() {
{privacyBoundaryCards.map((card) => ( @@ -698,7 +698,7 @@ export function PrivacyPage() {
@@ -725,7 +725,7 @@ export function PrivacyPage() {

- For browser-account, billing, release-access, or policy questions, contact {brandConfig.contact.email} and include whether the concern is public, protected, or native-runtime context. + For account, billing, release-access, or policy questions, contact {brandConfig.contact.email} and include whether the concern is on the public site, inside your account, or inside the desktop app.

@@ -785,8 +785,8 @@ export function TermsPage() {
    -
  • Browser access covers public pages, account, release, download, and operator/dashboard surfaces.
  • -
  • The simulator itself is delivered through the desktop lane unless a later browser-client branch is explicitly opened.
  • +
  • Browser access covers the public site, your account, release updates, download management, and dashboard tools.
  • +
  • The simulator itself is delivered through the desktop app unless a later browser-client branch is explicitly opened.
  • Downloaded builds and their public distribution pages remain subject to open-source notice and corresponding-source disclosure rules where applicable.
@@ -815,7 +815,7 @@ export function TermsPage() {
@@ -842,7 +842,7 @@ export function TermsPage() {
{digitalDeliveryCards.map((card) => ( @@ -930,7 +930,7 @@ export function ShippingPaymentPage() {
{operatorManualTracks.slice(1, 4).map((track) => ( @@ -951,27 +951,27 @@ export function ShippingPaymentPage() {
@@ -992,7 +992,7 @@ export function ShippingPaymentPage() {
{termsBoundaryCards.map((card) => ( @@ -1053,13 +1053,13 @@ export function ShippingPaymentPage() { /> -
+

- Write to {brandConfig.contact.email} for operator provisioning, studio rollout, payment, or release-surface billing questions. + Write to {brandConfig.contact.email} for account provisioning, team setup, payment, or release-surface billing questions.

diff --git a/website/src/pages/public-pages-features.tsx b/website/src/pages/public-pages-features.tsx index d1e829e..f5b687d 100644 --- a/website/src/pages/public-pages-features.tsx +++ b/website/src/pages/public-pages-features.tsx @@ -36,65 +36,65 @@ export function FeaturesPage() { <>
- + @@ -105,8 +105,8 @@ export function FeaturesPage() { />
{releaseStoryCards.map((card) => ( @@ -134,8 +134,8 @@ export function FeaturesPage() {
@@ -150,12 +150,12 @@ export function FeaturesPage() {
{roadmapHonestyCards.map((item) => ( diff --git a/website/src/pages/public-pages-guides.tsx b/website/src/pages/public-pages-guides.tsx index e5f7ab5..39eee01 100644 --- a/website/src/pages/public-pages-guides.tsx +++ b/website/src/pages/public-pages-guides.tsx @@ -42,41 +42,44 @@ export function BrowserExperiencePage() { <>
-

The browser is the public and protected operator shell

-

Use it for docs, pricing, release status, account access, notices, and browser-to-desktop pairing.

+

The website is your public and signed-in home base

+

Use it for docs, pricing, release status, account access, legal details, and website-to-desktop pairing.

-

The downloadable is the actual simulator

-

Use the desktop runtime for recognition, replay, coaching, higher-dimensional families, and packaged proof.

+

The desktop app is the real simulator

+

Use the desktop app for recognition, replay, coaching, higher-dimensional families, and the full training experience.

-

The current XR boundary is still explicit

-

The browser does not hide the fact that full headset/controller validation remains a separate native device packet.

+

Headset support is still being validated

+

The website does not hide the fact that broader headset and controller support still belongs to a later native device pass.

+ + Create account + Open desktop download - Open protected dashboard + Open dashboard Open help center @@ -85,39 +88,39 @@ export function BrowserExperiencePage() {
@@ -126,7 +129,7 @@ export function BrowserExperiencePage() { @@ -135,7 +138,7 @@ export function BrowserExperiencePage() {
@@ -162,23 +165,23 @@ export function HelpCenterPage() { <> @@ -193,36 +196,36 @@ export function HelpCenterPage() { />

Open support

-

Use the escalation route when the next job is launch recovery, entitlement review, or runtime issue routing.

+

Use the escalation route when the next job is launch recovery, account review, or desktop-app issue routing.

@@ -236,7 +239,7 @@ export function HelpCenterPage() { @@ -263,31 +266,31 @@ export function ContactPage() { <>

Email {brandConfig.contact.email} with the route, - platform, plan or account state, and whether the question is public, protected, or native runtime work. + platform, plan or account state, and whether the question is public, signed-in, or desktop-app work.

- The clearer the surface ownership is up front, the faster HyperTwist can separate account, package, runtime, and rollout questions. + The clearer the context is up front, the faster HyperTwist can separate account, package, runtime, and team questions.

@@ -302,7 +305,7 @@ export function ContactPage() { @@ -319,8 +322,8 @@ export function ContactPage() { />
-

The downloadable remains the runtime authority

-

Runtime issue reports should name the exact simulator family and build, not only the website route that led there.

+

The downloadable remains the source of simulator truth

+

Desktop-app issue reports should name the exact simulator family and build, not only the website route that led there.

- +
@@ -59,7 +59,7 @@ export function LaunchStatusPage() { @@ -67,20 +67,20 @@ export function LaunchStatusPage() {
diff --git a/website/src/pages/public-pages-marketing.tsx b/website/src/pages/public-pages-marketing.tsx index 1da2241..d12513b 100644 --- a/website/src/pages/public-pages-marketing.tsx +++ b/website/src/pages/public-pages-marketing.tsx @@ -73,24 +73,27 @@ function HomeHeroPanel() {

- HyperTwist is a native training environment for classic cube practice, recognition - and correction closure, replay explanation, coaching, higher-dimensional puzzle - families, and serious packaged study sessions. The web lane is intentionally narrower: - it owns access, documentation, release status, support, and pairing so the - downloadable can stay focused on the simulator itself. + HyperTwist is built for people who want more than a timer. Start on the website + when you want the story, plans, release notes, and setup guidance. Move into the + desktop app when you want the real experience: fast daily solves, guided recovery, + replay study, coaching, and deep 120‑cell or 5D sessions that feel like a place + you can keep returning to.

- - Download desktop app + + Create account + + + Get the desktop app - Why keep the web version? + See what the website is for - Open help center + Explore the help center - Open operator dashboard + Open your dashboard
@@ -101,12 +104,12 @@ function HomeHeroPanel() { className="hero-visual-card__image" />

- Browser shell for access, rollout, and support. Native Unreal runtime for the simulator. + One product, two roles: a polished front door on the web and a far deeper training room on desktop.

    -
  • Use the web for pricing, docs, release notes, notices, and protected downloads.
  • -
  • Use the downloadable for real cube-state workflows, higher-dimensional maps, and diagnostics.
  • -
  • Read headset and controller support as a native device-validation track, not as a browser feature claim.
  • +
  • Use the website for pricing, docs, release notes, legal details, and private downloads.
  • +
  • Use the desktop app for real cube-state workflows, replay review, and higher-dimensional maps.
  • +
  • Use keyboard and mouse today, with XR kept honest until packaged device proof is complete.
@@ -126,7 +129,7 @@ function HomeShippingNowSection() { return (
{shippingNowCards.map((item) => ( @@ -144,7 +147,7 @@ function HomeCapabilityPillarsSection() { return (
{capabilityPillars.map((pillar) => ( @@ -161,8 +164,8 @@ function HomeCapabilityPillarsSection() { function HomeRoadmapHonestySection() { return (
{roadmapHonestyCards.map((item) => ( @@ -178,30 +181,30 @@ function HomeRoadmapHonestySection() { function HomeDeliverySurfacesSection() { return (
-

Browser account and operator shell

-

Authenticated browser access for release status, desktop pairing, notices, and operator state.

+

Website account and dashboard

+

Signed-in web access for release status, desktop pairing, notices, and account management.

Open dashboard
-

Desktop download and package lane

-

Public download guidance for the native Unreal build, with legal linkage already wired in.

+

Desktop download and release path

+

Download guidance for the native Unreal build, with release notes and notices kept close to the build itself.

Open download center
-

Checkout and notices discipline

-

Paddle-ready pricing plus public notices surfaces for any downloadable build containing MPL-covered material.

+

Plans, checkout, and notices

+

Pricing, checkout, and public notices stay visible together so buying and download decisions are easy to understand.

Review notices @@ -215,7 +218,7 @@ function HomeFirstSessionSection() { return (
{operatorManualTracks.slice(0, 3).map((track) => ( @@ -263,14 +266,14 @@ function ResourcesFinderSection({ onQueryChange: (value: string) => void }) { return ( -
+
onQueryChange(event.target.value)} - placeholder="Search training, rollout, notices..." + placeholder="Search training, downloads, notices..." />
{filteredCollections.map((collection) => ( @@ -295,42 +298,42 @@ function ResourcesDirectRoutesSection() {

Browser guide

-

The public explanation of what the web version is for, what it is weaker at, and when to move into the downloadable.

+

The public explanation of what the web experience is for, where the desktop app goes deeper, and when to move into it.

Feature atlas

-

One public page for current capability, surface boundaries, and release status.

+

One public page for puzzle families, controls, higher-dimensional depth, and what ships today.

Help center

-

Knowledge-base style guidance for onboarding, controls, release handoff, and rollout-safe troubleshooting.

+

Knowledge-base style guidance for onboarding, controls, release handoff, and practical troubleshooting.

Getting started

-

The canonical first-session path from browser access into the packaged desktop runtime.

+

The clearest first-session path from website account setup into the downloadable app.

Launch status

-

The canonical public checklist for early access, release authority, and rollout follow-through.

+

The public checklist for early access, release readiness, and current availability.

Docs landing

-

Product-facing documentation, boundaries, and rollout guidance.

+

Product-facing documentation, controls, setup, and deeper guidance.

Support

-

Contact, rollout questions, and account/download help.

+

Contact, account help, download help, and setup questions.

Contact

-

The direct operator contact route for access, runtime, rollout, pricing, and notice follow-through.

+

The direct contact route for access, desktop-app issues, pricing, and team planning.

@@ -345,8 +348,8 @@ function ResourcesDirectRoutesSection() { function ResourcesOperatorPlaybooksSection() { return (
{operatorPlaybooks.map((playbook) => ( @@ -367,8 +370,8 @@ function ResourcesOperatorPlaybooksSection() { function ResourcesDeploymentSnapshotSection() { return (
{deploymentReadinessTracks.map((track) => ( @@ -393,40 +396,40 @@ export function HomeLanding() { <>
@@ -434,7 +437,7 @@ export function HomeLanding() { @@ -444,12 +447,12 @@ export function HomeLanding() { @@ -484,11 +487,11 @@ export function HomeLanding() { - +
@@ -504,13 +507,13 @@ export function AboutPage() { <>
@@ -523,14 +526,14 @@ export function AboutPage() {
@@ -538,7 +541,7 @@ export function AboutPage() {

It treats higher-dimensional puzzles as first-class work

-

120-cell and 5D runtime ownership are not hand-wavy aspirations. They are part of the current product truth.

+

120‑cell and 5D study are not hand-wavy aspirations. They are part of the current product.

@@ -547,8 +550,8 @@ export function AboutPage() {
-

It separates browser shell from simulator truth

-

The public web surface helps operators access the product without pretending the browser already replaces the desktop runtime.

+

It keeps the website and simulator honest

+

The public website helps people access the product without pretending the browser already replaces the desktop app.

@@ -561,13 +564,13 @@ export function AboutPage() {
{operatorManualTracks.map((track) => ( @@ -586,7 +589,7 @@ export function AboutPage() { @@ -594,7 +597,7 @@ export function AboutPage() {
{deploymentReadinessTracks.map((track) => ( @@ -626,7 +629,7 @@ export function AboutPage() {
@@ -642,7 +645,7 @@ export function AboutPage() { @@ -660,13 +663,13 @@ export function ResourcesPage() { <> - + @@ -713,7 +716,7 @@ export function ResourcesPage() { /> @@ -750,13 +753,13 @@ export function ResourcesPage() { platform={windowsValidationPlatform} actions={[ { to: '/download', label: 'Open download center' }, - { to: '/app', label: 'Open operator dashboard' }, + { to: '/app', label: 'Open dashboard' }, ]} /> @@ -771,12 +774,12 @@ function GettingStartedPageContent({ <> @@ -791,7 +794,7 @@ function GettingStartedPageContent({ />
+ actions={[ + { to: '/download', label: 'Open download center' }, + { to: '/app', label: 'Open dashboard' }, + ]} + /> ) @@ -882,13 +885,13 @@ export function GettingStartedPage() { <> - +

Browser guide

-

Open the public explanation of the web version, protected dashboard, and downloadable boundary.

+

Open the public explanation of the website companion, account dashboard, and desktop app.

@@ -941,11 +944,11 @@ export function DocsPage() { @@ -981,7 +984,7 @@ export function DocsPage() {
@@ -1022,7 +1025,7 @@ export function DocsPage() { @@ -1031,7 +1034,7 @@ export function DocsPage() { @@ -1051,12 +1054,12 @@ export function DocsPage() { @@ -1083,16 +1086,16 @@ export function SupportPage() { <> {selectedSupportTopic ? ( -
+

{selectedSupportTopic.title}

{selectedSupportTopic.description}

@@ -1102,8 +1105,8 @@ export function SupportPage() { {selectedSupportTopicKey ? ( topic.topicKey === selectedSupportTopicKey)} selectedTopicKey={selectedSupportTopicKey} /> @@ -1126,12 +1129,12 @@ export function SupportPage() {
- +
{operatorPlaybooks.map((playbook) => ( @@ -1198,13 +1201,13 @@ export function SupportPage() { @@ -1217,7 +1220,7 @@ export function SupportPage() {
{digitalDeliveryCards.map((card) => ( @@ -1236,7 +1239,7 @@ export function SupportPage() {
{privacyBoundaryCards.map((card) => ( @@ -1255,7 +1258,7 @@ export function SupportPage() {
{supportEscalationCards.map((card) => ( @@ -1283,17 +1286,17 @@ export function ChangelogPage() { <>
{releasePacketCards.map((entry) => ( @@ -1313,7 +1316,7 @@ export function ChangelogPage() {
{changelogEntries.map((entry) => ( @@ -1328,7 +1331,7 @@ export function ChangelogPage() {
{releaseStoryCards.map((card) => ( @@ -1345,16 +1348,16 @@ export function ChangelogPage() {
- +
{releaseRolloutChecklist.map((card) => ( diff --git a/website/src/public-route-registry.json b/website/src/public-route-registry.json index 0684958..01c2b46 100644 --- a/website/src/public-route-registry.json +++ b/website/src/public-route-registry.json @@ -3,8 +3,8 @@ "path": "/", "label": "Home", "loaderTitle": "Loading HyperTwist...", - "loaderEyebrow": "Public release shell", - "loaderDescription": "Loading the public product story, current launch status, and browser-versus-desktop authority map.", + "loaderEyebrow": "Public website", + "loaderDescription": "Loading the full HyperTwist story, the current access snapshot, and the easiest path into the desktop app.", "nav": true, "footer": false, "crawlable": true @@ -13,8 +13,8 @@ "path": "/browser", "label": "Browser", "loaderTitle": "Browser access guide", - "loaderEyebrow": "Web version role", - "loaderDescription": "Loading the browser-versus-downloadable boundary, protected dashboard handoff, and the current web-lane purpose.", + "loaderEyebrow": "Browser companion", + "loaderDescription": "Loading how the website, account access, and desktop app work together.", "nav": true, "footer": true, "crawlable": true @@ -24,7 +24,7 @@ "label": "Features", "loaderTitle": "Feature atlas", "loaderEyebrow": "Capability atlas", - "loaderDescription": "Loading the shipped feature map, higher-dimensional runtime state, and explicit desktop-first boundaries.", + "loaderDescription": "Loading the full feature lineup across classic cubes, 120‑cell, 5D, replay, coaching, and guided training.", "nav": true, "footer": true, "crawlable": true @@ -34,7 +34,7 @@ "label": "About", "loaderTitle": "About HyperTwist", "loaderEyebrow": "Product narrative", - "loaderDescription": "Loading the mission, higher-dimensional seriousness, and current control-boundary truth behind the product.", + "loaderDescription": "Loading the HyperTwist story, the training vision, and why the product spans both web and desktop.", "nav": true, "footer": true, "crawlable": true @@ -43,8 +43,8 @@ "path": "/resources", "label": "Resources", "loaderTitle": "Resources", - "loaderEyebrow": "Public reference portal", - "loaderDescription": "Loading rollout-safe resources, simulator guidance, and current higher-dimensional operator references.", + "loaderEyebrow": "Resource library", + "loaderDescription": "Loading guides, manuals, and training references for players, teams, and studios.", "nav": false, "footer": true, "crawlable": true @@ -53,8 +53,8 @@ "path": "/help", "label": "Help Center", "loaderTitle": "Help center", - "loaderEyebrow": "Operator knowledge base", - "loaderDescription": "Loading onboarding, control truth, browser-to-desktop guidance, and rollout-safe troubleshooting.", + "loaderEyebrow": "Help center", + "loaderDescription": "Loading setup, controls, downloads, and practical troubleshooting.", "nav": true, "footer": true, "crawlable": true @@ -63,8 +63,8 @@ "path": "/getting-started", "label": "Getting Started", "loaderTitle": "Getting started", - "loaderEyebrow": "Operator onboarding", - "loaderDescription": "Loading the first-session quickstart, browser-to-desktop pairing flow, and the current desktop-first runtime boundary.", + "loaderEyebrow": "Getting started", + "loaderDescription": "Loading the first-session path from account setup to the desktop app.", "nav": false, "footer": true, "crawlable": true @@ -73,8 +73,8 @@ "path": "/launch-status", "label": "Launch Status", "loaderTitle": "Launch status", - "loaderEyebrow": "Launch authority", - "loaderDescription": "Loading the canonical public launch-readiness checklist, release status, and early-access authority map.", + "loaderEyebrow": "Access status", + "loaderDescription": "Loading current availability, release progress, and access options.", "nav": false, "footer": true, "crawlable": true @@ -84,7 +84,7 @@ "label": "Docs", "loaderTitle": "Documentation", "loaderEyebrow": "Public manual", - "loaderDescription": "Loading the feature-registry-backed manual, rollout doctrine, and browser-versus-desktop usage guide.", + "loaderDescription": "Loading the complete HyperTwist manual, controls, and setup guidance.", "nav": false, "footer": true, "crawlable": true @@ -93,8 +93,8 @@ "path": "/support", "label": "Support", "loaderTitle": "Support", - "loaderEyebrow": "Operator help lane", - "loaderDescription": "Loading rollout guidance, account and entitlement help, and browser-to-desktop escalation routes.", + "loaderEyebrow": "Support", + "loaderDescription": "Loading help routes for account access, downloads, pricing, and setup.", "nav": false, "footer": true, "crawlable": true @@ -103,8 +103,8 @@ "path": "/contact", "label": "Contact", "loaderTitle": "Contact HyperTwist", - "loaderEyebrow": "Human help lane", - "loaderDescription": "Loading operator contact paths, escalation packets, and release-aware support follow-through.", + "loaderEyebrow": "Contact", + "loaderDescription": "Loading direct contact routes for support, teams, and release questions.", "nav": false, "footer": true, "crawlable": true @@ -114,7 +114,7 @@ "label": "Release notes", "loaderTitle": "Release notes", "loaderEyebrow": "Public release history", - "loaderDescription": "Loading recent browser, package, control-boundary, and rollout changes from the active shipping lane.", + "loaderDescription": "Loading recent product updates across the website, desktop app, controls, and releases.", "nav": false, "footer": true, "crawlable": true @@ -123,8 +123,8 @@ "path": "/pricing", "label": "Pricing", "loaderTitle": "Pricing", - "loaderEyebrow": "Paddle-ready plans", - "loaderDescription": "Loading plan access, public launch readiness, and the current desktop-first distribution model.", + "loaderEyebrow": "Pricing", + "loaderDescription": "Loading plans, checkout status, and what each plan unlocks.", "nav": true, "footer": true, "crawlable": true @@ -134,7 +134,7 @@ "label": "Download", "loaderTitle": "Download center", "loaderEyebrow": "Desktop distribution", - "loaderDescription": "Loading the current release manifest status, package proof, and browser-to-desktop pairing guidance.", + "loaderDescription": "Loading release availability, desktop build details, and install guidance.", "nav": true, "footer": true, "crawlable": true @@ -144,7 +144,7 @@ "label": "Open Source Notices", "loaderTitle": "Open source notices", "loaderEyebrow": "Distribution references", - "loaderDescription": "Loading notices, corresponding-source status, and public legal follow-through for downloadable builds.", + "loaderDescription": "Loading open-source notices, source links, and release-related legal information.", "nav": false, "footer": true, "crawlable": true @@ -153,8 +153,8 @@ "path": "/privacy", "label": "Privacy", "loaderTitle": "Privacy", - "loaderEyebrow": "Public policy surface", - "loaderDescription": "Loading the browser-account privacy model, desktop-link boundary, and distribution-safe data handling notes.", + "loaderEyebrow": "Privacy", + "loaderDescription": "Loading how account data, billing, and the desktop app stay clearly separated.", "nav": false, "footer": true, "crawlable": true @@ -163,8 +163,8 @@ "path": "/terms", "label": "Terms", "loaderTitle": "Terms", - "loaderEyebrow": "Public policy surface", - "loaderDescription": "Loading access terms, protected download boundaries, and the current desktop-first simulator model.", + "loaderEyebrow": "Terms", + "loaderDescription": "Loading access terms for accounts, downloads, and desktop use.", "nav": false, "footer": true, "crawlable": true @@ -174,7 +174,7 @@ "label": "Shipping & Payment", "loaderTitle": "Shipping & payment", "loaderEyebrow": "Distribution policy", - "loaderDescription": "Loading the digital-delivery model, Paddle-ready billing, and protected release follow-through.", + "loaderDescription": "Loading digital delivery, billing, and purchase guidance.", "nav": false, "footer": true, "crawlable": true @@ -183,8 +183,8 @@ "path": "/login", "label": "Log in", "loaderTitle": "Log in", - "loaderEyebrow": "Browser account access", - "loaderDescription": "Preparing sign-in, safe next-step routing, and protected release continuity before the operator shell opens.", + "loaderEyebrow": "Account access", + "loaderDescription": "Preparing sign-in, account access, and the path into your dashboard and downloads.", "nav": false, "footer": false, "crawlable": false @@ -193,8 +193,8 @@ "path": "/register", "label": "Create account", "loaderTitle": "Create account", - "loaderEyebrow": "Browser account access", - "loaderDescription": "Preparing account creation, protected release follow-through, and browser-to-desktop continuity for first launch.", + "loaderEyebrow": "Create account", + "loaderDescription": "Preparing account creation, dashboard access, and your first desktop download.", "nav": false, "footer": false, "crawlable": false diff --git a/website/src/router/AppRouteTree.tsx b/website/src/router/AppRouteTree.tsx index 5330b51..dc3c874 100644 --- a/website/src/router/AppRouteTree.tsx +++ b/website/src/router/AppRouteTree.tsx @@ -15,39 +15,39 @@ const NoticesPage = lazy(() => import('../pages/app-pages').then((m) => ({ defau const protectedAppLoaders = { dashboard: { title: 'Loading dashboard...', - eyebrow: 'Protected operator shell', + eyebrow: 'Signed-in dashboard', description: - 'Restoring account state, release authority, package proof, and browser-to-desktop pairing inside the signed-in operator lane.', + 'Restoring your account, release status, desktop pairing, and download readiness.', }, downloads: { title: 'Loading downloads...', - eyebrow: 'Protected release lane', + eyebrow: 'Signed-in downloads', description: - 'Resolving entitled desktop targets, current package proof, and rollout references before the signed-in download surface opens.', + 'Preparing your available desktop builds, package checks, and release notes.', }, launchStatus: { title: 'Loading launch status...', - eyebrow: 'Protected rollout authority', + eyebrow: 'Launch status', description: - 'Restoring the signed-in launch checklist, release references, and packaged proof before protected rollout follow-through resumes.', + 'Restoring the current release checklist, launch notes, and package proof.', }, browserAccess: { title: 'Loading browser access...', - eyebrow: 'Protected browser shell', + eyebrow: 'Browser companion', description: - 'Restoring the signed-in browser state, release guidance, and explicit browser-versus-desktop boundaries.', + 'Restoring the signed-in website experience and the current web-versus-desktop guide.', }, account: { title: 'Loading account...', - eyebrow: 'Protected account lane', + eyebrow: 'Account', description: - 'Refreshing the signed-in account view, current plan state, and release-access continuity before desktop follow-through resumes.', + 'Refreshing your plan, access, and release details.', }, notices: { title: 'Loading notices...', - eyebrow: 'Protected distribution references', + eyebrow: 'Release notices', description: - 'Restoring signed-in notices, corresponding-source references, and download/distribution guidance inside the protected release shell.', + 'Restoring notices, source links, and release references for the current desktop build.', }, } as const diff --git a/website/src/site-config.ts b/website/src/site-config.ts index 65dfe5d..ead2ef5 100644 --- a/website/src/site-config.ts +++ b/website/src/site-config.ts @@ -27,7 +27,7 @@ export const brandConfig = { brandName: 'HyperTwist', legalName: 'HyperTwist', domain: 'hypertwist.app', - tagline: 'Native cube and hypercube training, from first solve to 120-cell.', + tagline: 'Desktop cubing and hypercubing, from first solves to 120‑cell mastery.', contact: { email: readTrimmedEnv('VITE_SUPPORT_EMAIL', 'hello@hypertwist.app'), emailHref: `mailto:${readTrimmedEnv('VITE_SUPPORT_EMAIL', 'hello@hypertwist.app')}`, @@ -55,7 +55,7 @@ export const planCatalog = [ price: 'Free', ctaLabel: 'Create account', ctaHref: buildRegisterPath('/app'), - notes: 'Create a HyperTwist account to read the operator dashboard, product manual, release notes, and desktop onboarding flow before you subscribe.', + notes: 'Create your HyperTwist account to open the dashboard, read the manual, follow release notes, and get ready for your first desktop session.', features: [ 'Browser account and dashboard access', 'Public manual, release notes, and resource center', @@ -69,51 +69,51 @@ export const planCatalog = [ price: readTrimmedEnv('VITE_PLAN_PRICE_OPERATOR', 'Launch pricing via Paddle'), ctaLabel: operatorCheckoutUrl ? 'Subscribe with Paddle' : 'Create account for download access', ctaHref: operatorCheckoutUrl || buildProtectedDownloadPath('windows'), - notes: 'Desktop-first recognition, replay, training, higher-dimensional runtime ownership, and protected Windows package access for active solvers.', + notes: 'Unlock the desktop simulator for recognition, replay review, guided training, and higher-dimensional practice on Windows.', features: [ 'Protected desktop download access', 'Browser-issued desktop-link token handoff', - 'Recognition, replay, and coaching ownership', - 'Classic-cube package and validation lane access', - ], - }, - { - key: 'studio', - name: 'Studio', - price: readTrimmedEnv('VITE_PLAN_PRICE_STUDIO', 'Contact for launch readiness'), - ctaLabel: studioCheckoutUrl ? 'Open studio checkout' : 'Talk to HyperTwist', - ctaHref: studioCheckoutUrl || '/contact', - notes: 'Higher-dimensional training programs, deployment support, and release/package coordination for studios, educators, and rollout owners.', - features: [ - 'Magic120Cell and 5D operator status', - 'Release planning and deployment coordination', - 'Desktop distribution and legal-notice readiness', - 'Custom support for rollout and training programs', + 'Recognition, replay review, and coaching tools', + 'Classic-cube training plus verified package delivery', ], }, + { + key: 'studio', + name: 'Studio', + price: readTrimmedEnv('VITE_PLAN_PRICE_STUDIO', 'Contact for launch readiness'), + ctaLabel: studioCheckoutUrl ? 'Open studio checkout' : 'Talk to HyperTwist', + ctaHref: studioCheckoutUrl || '/contact', + notes: 'For studios, educators, and advanced teams who want guided onboarding, higher-dimensional programs, and hands-on release support.', + features: [ + 'Magic120Cell and 5D training access planning', + 'Release planning and deployment coordination', + 'Desktop distribution and notice-readiness support', + 'Custom onboarding for classes, labs, and training teams', + ], + }, ] as const export const downloadTargets = [ { platformKey: 'windows', platform: 'Windows', - subtitle: 'Primary shipping lane', + subtitle: 'Primary desktop release', configured: readBooleanEnv('VITE_WINDOWS_RELEASE_CONFIGURED', 'VITE_WINDOWS_DOWNLOAD_CONFIGURED'), - details: 'Current packaged validation is strongest on the Windows Unreal lane.', + details: 'The current packaged build and validation proof are strongest on Windows.', }, { platformKey: 'macos', platform: 'macOS', - subtitle: 'Planned distribution surface', + subtitle: 'Planned release', configured: readBooleanEnv('VITE_MAC_RELEASE_CONFIGURED', 'VITE_MAC_DOWNLOAD_CONFIGURED'), details: 'macOS distribution will appear here when a signed desktop build is ready for account-gated delivery.', }, { platformKey: 'linux', platform: 'Linux', - subtitle: 'Operator-targeted later lane', + subtitle: 'Later desktop release', configured: readBooleanEnv('VITE_LINUX_RELEASE_CONFIGURED', 'VITE_LINUX_DOWNLOAD_CONFIGURED'), - details: 'Linux distribution will appear here when the operator-targeted package lane is ready.', + details: 'Linux distribution will appear here when a supported desktop package is ready.', }, ] as const satisfies readonly DownloadTarget[] @@ -138,4 +138,4 @@ export const launchReadiness = { } as const export const paddleReadyDescription = - 'HyperTwist is a desktop-first training environment for classic cube practice, recognition-assisted reconstruction, replay explanation, coaching, 120-cell and 5D exploration, and browser-based operator access. Delivery is digital-only: public pages explain the product, account routes manage subscription and entitlement, and the downloadable desktop runtime performs the real simulator work. Pricing and checkout are wired for Paddle, while public legal pages keep open-source notices and corresponding-source disclosure attached to shipped downloadable builds.' + 'Choose a plan, unlock your account, and keep downloads, billing, release notes, and support in one place. Then move into the desktop app for the full HyperTwist simulator, from guided classic-cube practice to serious 120‑cell and 5D sessions.' diff --git a/website/src/site-data.ts b/website/src/site-data.ts index 216ab4f..a9f3390 100644 --- a/website/src/site-data.ts +++ b/website/src/site-data.ts @@ -1,83 +1,83 @@ import { brandConfig, mplSourceUrl, openSourceRepoUrl, publicDocsUrl, releaseNotesUrl } from './site-config' export const heroMetrics = [ - { label: 'Current runtime center', value: 'Native Unreal' }, - { label: 'Higher-dimensional ownership', value: '120-cell + 5D' }, - { label: 'Browser role', value: 'Account + release shell' }, - { label: 'Desktop package', value: 'Validated Windows lane' }, + { label: 'Main simulator', value: 'Native Unreal' }, + { label: 'Advanced puzzle families', value: '120‑cell + 5D' }, + { label: 'Website companion', value: 'Accounts + downloads' }, + { label: 'Windows build status', value: 'Validated build' }, ] as const export const capabilityPillars = [ { title: 'Recognition to reconstruction', - description: 'Classic-cube intake, correction closure, browser-assisted recognition, and solve guidance are already first-party owned surfaces.', + description: 'Move from scrambled cube observations into reconstruction, correction, and guided solves without leaving the HyperTwist flow.', }, { title: 'Replay, coaching, and analytics', - description: 'Replay capture, explanation, leaderboard persistence, training analytics, and operator diagnostics are part of the current shipping lane.', + description: 'Review replays, revisit sessions, follow guided practice, and keep your progress visible instead of trapped inside a timer alone.', }, { title: 'Higher-dimensional seriousness', - description: 'Hyper puzzle catalog, replay verification, 120-cell and 5D runtime ownership, and non-Euclidean tiling state are all represented honestly.', + description: 'HyperTwist goes far beyond the classic cube with dedicated 120‑cell, 5D, and non-Euclidean study experiences.', }, { title: 'Desktop-first distribution', - description: 'Browser account access supports the operator, while the real simulator and package-validation story remain desktop-first and Unreal-backed.', + description: 'The website gets you started, while the fidelity, performance, and full simulator depth stay in the downloadable Unreal app.', }, { - title: 'Operator adjunct intelligence', - description: 'Speech capture, provider-neutral routing, usage governance, and continuity/provenance families already exist as real operator-grade adjunct surfaces around the simulator.', + title: 'Companion systems that go deeper', + description: 'Speech capture, continuity, and advanced review tools are already present for people who want a richer training routine.', }, ] as const export const deliverySurfaceCards = [ { title: 'Public website', - description: 'Use the web surface for product positioning, account entry, release notes, notices, pricing, and support-safe onboarding.', + description: 'Use the website to learn what HyperTwist does, create an account, compare plans, read release notes, and get help.', bullets: [ - 'Explains the current desktop-first product and future branches in plain language', - 'Carries public docs, release notes, package proof, and legal links', - 'Keeps anonymous pages informative while protected routes handle actual downloads', + 'Explains the current web-and-desktop product clearly for new players, teams, and buyers.', + 'Carries public docs, release notes, desktop build details, and legal links.', + 'Keeps anonymous pages informative while signed-in routes handle actual downloads.', ], }, { - title: 'Protected browser dashboard', - description: 'Use the browser dashboard when identity, subscription, entitlement, billing, or pairing state matters.', + title: 'Signed-in dashboard', + description: 'Use the dashboard when your account, subscription, billing, or desktop pairing state matters.', bullets: [ - 'Shows account, auth, billing, and release readiness status', - 'Generates desktop-link tokens for safe browser-to-desktop handoff', - 'Keeps plan-gated download access in the protected dashboard lane', + 'Shows account, auth, billing, and release status.', + 'Generates desktop-link tokens for safe website-to-desktop pairing.', + 'Keeps plan-gated download access tied to your signed-in account.', ], }, { - title: 'Native Unreal desktop runtime', - description: 'Use the desktop build for the real simulator, package-validated training maps, and higher-dimensional execution.', + title: 'Desktop simulator', + description: 'Use the desktop build for the real simulator, verified training maps, and higher-dimensional execution.', bullets: [ - 'Owns recognition, replay, coaching, and packaged training behavior', - 'Owns the current higher-dimensional 120-cell and 5D runtime lane', - 'Owns the device/runtime integrations the public website does not claim', + 'Owns recognition, replay, coaching, and packaged training behavior.', + 'Owns the current higher-dimensional 120‑cell and 5D runtime experiences.', + 'Owns the device integrations the public website does not claim.', ], }, { - title: 'Future browser simulator branch', + title: 'Future browser-only simulator', description: 'A full browser simulator would be a separate future product branch, not the current downloadable simulator.', bullets: [ - 'Not the current training surface', - 'Does not displace the current desktop-first simulator', - 'Would need its own runtime quality, backend contract, and product proof before launch', + 'Not the current training surface.', + 'Does not displace the current desktop-first simulator.', + 'Would need its own runtime quality, backend contract, and product proof before launch.', ], }, ] as const export const browserDesktopRealityCards = [ { - title: 'What the website is for', - posture: 'Public and protected browser shell', - description: 'Keep the web lane because product access, release notes, billing, notices, and operator onboarding should stay inspectable outside the simulator.', + title: 'Why the website exists', + posture: 'Website and account hub', + description: 'The website is the easiest place to discover HyperTwist, create your account, compare plans, stay current, and unlock the desktop app.', bullets: [ - 'The website owns public docs, pricing, release notes, notices, and support-safe onboarding guidance.', - 'The protected dashboard owns account state, entitlement, protected downloads, and browser-to-desktop pairing.', - 'This keeps release and commercial context visible without turning the simulator into a checkout or auth shell.', + 'Use it for product story, account access, pricing, release notes, help, and download handoff.', + 'Use the signed-in dashboard for plan status, private downloads, and desktop pairing without exposing your password inside the app.', + 'That keeps HyperTwist welcoming and easy to navigate before you ever open the simulator.', ], action: { to: '/docs', @@ -85,13 +85,13 @@ export const browserDesktopRealityCards = [ }, }, { - title: 'What the desktop runtime is for', - posture: 'Native simulator authority', - description: 'Keep the real simulator native because the desktop runtime is where package proof, training quality, device/runtime integration, and higher-dimensional execution are actually owned.', + title: 'Why the desktop app exists', + posture: 'Desktop training experience', + description: 'The desktop app is where HyperTwist becomes a place to practice, study, and return to every day.', bullets: [ - 'The desktop lane owns recognition, replay, coaching, analytics, and packaged training behavior.', - 'It owns the current dedicated-family Magic120Cell and MagicCube5D runtime lanes.', - 'It is the only current surface that can honestly claim simulator execution authority.', + 'This is where recognition, replay, coaching, analytics, and session continuity already feel like one connected training flow.', + 'This is also where Magic120Cell and MagicCube5D already become real, explorable sessions instead of abstract promises.', + 'If you want the full HyperTwist experience, this is the product surface that delivers it.', ], action: { to: '/download', @@ -99,28 +99,28 @@ export const browserDesktopRealityCards = [ }, }, { - title: 'Why the browser is intentionally narrower', - posture: 'Deliberate product boundary', - description: 'The browser lane is useful precisely because it does not pretend to replace the simulator.', + title: 'Why the website feels fast and focused', + posture: 'Clear product split', + description: 'The website stays focused so getting in, buying, learning, and staying updated feel effortless instead of buried inside a heavy training tool.', bullets: [ - 'It does not claim package-validated training behavior, higher-dimensional execution, or device/runtime integration authority.', - 'Low-latency simulator input, packaged runtime ownership, higher-dimensional scene execution, and any future serious controller/VR completion still remain desktop-owned.', - 'It keeps identity, billing, release, and legal-distribution work outside the native runtime where operators can review it more safely.', - 'It preserves a clean browser-to-desktop pairing boundary instead of collapsing access, rollout, and simulator execution into one brittle shell.', + 'It does not pretend to be the full simulator, the advanced puzzle room, or the device-heavy practice surface.', + 'Fast controls, richer visuals, deeper puzzle rendering, and future XR growth stay on the native side where they belong.', + 'That split keeps sign-in, billing, downloads, and legal details easy to understand.', + 'You get a clean front door on the web and a much stronger training room on desktop.', ], action: { to: '/app', - label: 'Open operator dashboard', + label: 'Open dashboard', }, }, { - title: 'Current input, XR, and settings truth', - posture: 'Available now versus future device proof', - description: 'HyperTwist already ships meaningful desktop control/settings ownership, but it does not market unfinished XR/controller widening as complete.', + title: 'Controls and device support today', + posture: 'What you can use today', + description: 'Keyboard and mouse are already a real, satisfying way to use HyperTwist today, while broader headset support remains clearly marked as still in validation.', bullets: [ - 'Classic keyboard, mouse/touch classic-cube control, viewer camera settings, bounded camera-export continuity, immersive presets, session-local immersive recall, and dedicated-family selector, session, scene, and view ownership are real today.', - 'The native operator surfaces now also expose concrete Magic120Cell and MagicCube5D session-surface, interactive-scene, persistence-boundary, and state-semantics ownership instead of hiding that proof behind softer settings summaries.', - 'Broader headset/controller rollout still requires packaged device proof before HyperTwist markets it as a finished cross-device VR lane.', + 'Classic keyboard play, pointer control, orbit, zoom, camera settings, immersive presets, and dedicated-family selectors are already live.', + 'Magic120Cell and MagicCube5D already carry real session, scene, projection, persistence, and state ownership inside the desktop runtime.', + 'Broader headset and controller rollout still needs packaged device proof before HyperTwist should market it as a finished cross-device VR lane.', ], action: { to: '/features', @@ -141,112 +141,112 @@ export type ProductSurfaceMatrixRow = { export const productSurfaceMatrixRows = [ { title: 'Public website', - posture: 'Public product shell', - description: 'This is the anonymous-safe product surface for positioning, release references, account entry, and operator-safe onboarding.', + posture: 'Public website', + description: 'This is the public front door for product discovery, account entry, release notes, and onboarding.', owns: [ - 'Public docs, pricing, release notes, legal notices, and support-safe rollout guidance.', - 'The first step into account creation, sign-in, and platform-aware download routing.', - 'Public access truth without exposing entitled package delivery on an anonymous route.', + 'Public docs, pricing, release notes, legal pages, and the first step into downloads.', + 'The clearest place to compare plans, understand the product, and decide whether to create an account.', + 'A trustworthy overview of what ships today without exposing private downloads on an anonymous page.', ], doesNotClaim: [ 'The native Unreal simulator runtime.', - 'Packaged higher-dimensional execution or device/runtime integration.', - 'The optional full-browser simulator branch as a live product lane.', + 'The packaged higher-dimensional sessions or device-heavy practice flow.', + 'A live full-browser simulator edition.', ], - nextStep: 'Start here when discovery, documentation, release notes, or public rollout context matters.', + nextStep: 'Start here when you are evaluating HyperTwist, reading the manual, or getting ready to open your account.', }, { - title: 'Protected browser dashboard', - posture: 'Signed-in operator shell', - description: 'This is the account-aware browser lane for entitlement, account health, billing, protected notices, and desktop pairing.', + title: 'Signed-in dashboard', + posture: 'Account dashboard', + description: 'This is the signed-in website experience for account health, billing, private downloads, and desktop pairing.', owns: [ - 'Live session, billing, entitlement, and release-manifest viewer state.', - 'A dedicated signed-in launch-status route for rollout status, packaged proof, and protected next-step interpretation.', - 'Desktop-link token issuance and protected follow-through after sign-in.', - 'Operator-facing release, notice, and download-center context that should not sit on public pages.', + 'Live session, billing, plan status, and private download context.', + 'Desktop-link token issuance so the app can pair cleanly with your account.', + 'Signed-in launch and access guidance that should not live on public pages.', + 'Account-facing notices, release details, and pairing tools.', ], doesNotClaim: [ 'The simulator execution loop itself.', 'Higher-dimensional packaged runtime behavior.', - 'General desktop-runtime telemetry ownership beyond the bounded pairing and release surfaces.', + 'A replacement for the desktop training room.', ], - nextStep: 'Use this surface once identity, plan, entitlement, or protected release access matters.', + nextStep: 'Open this once your plan, downloads, pairing, or account status starts to matter.', }, { - title: 'Embedded simulator browser shell', - posture: 'In-simulator browser adjunct', - description: 'This is the browser runtime that ships inside the desktop product for bounded simulator-side interaction, not the public website.', + title: 'Embedded simulator web tools', + posture: 'In-app web tools', + description: 'These are the web-powered tools that live inside the desktop app itself, not on the public site.', owns: [ - 'The current MagicTile host, browser-assisted recognition shell segments, and typed runtime-ready or runtime-status envelopes.', - 'Bounded operator diagnostics that stay attached to the native training and dashboard surfaces.', - 'A first-party browser bridge inside the desktop runtime instead of a separate public-web simulator claim.', + 'The current MagicTile host and the browser-assisted recognition helper.', + 'Focused runtime diagnostics that stay attached to the native training surfaces.', + 'A first-party browser bridge inside the desktop app instead of a separate public-web simulator claim.', ], doesNotClaim: [ - 'Public auth, pricing, checkout, or legal-distribution ownership.', + 'Public auth, pricing, checkout, or legal pages.', 'Standalone full-browser simulator parity.', - 'A reopened native renderer-port branch for MagicTile.', + 'A reopened native renderer path for MagicTile.', ], - nextStep: 'Treat this as an in-product runtime adjunct when simulator-side browser interaction or diagnostics are the real need.', + nextStep: 'Think of this as an in-product companion surface when a desktop session needs web-powered help or diagnostics.', }, { title: 'Native Unreal desktop runtime', - posture: 'Simulator authority', - description: 'This remains the real product center for training quality, packaged proof, replay, recognition, and higher-dimensional runtime ownership.', + posture: 'Desktop simulator', + description: 'This remains the real center of HyperTwist for practice, replay, recognition, coaching, and higher-dimensional study.', owns: [ - 'Recognition, correction, replay, coaching, analytics, and packaged training behavior.', - 'Dedicated-family Magic120Cell and MagicCube5D runtime-state, session/scene, projection, and persistence ownership.', - 'The device, package, and runtime lane that public and protected browser surfaces deliberately do not absorb.', + 'Recognition, correction, replay, coaching, analytics, and the actual training loop.', + 'Dedicated Magic120Cell and MagicCube5D runtime-state, session, projection, and persistence ownership.', + 'The device, package, and runtime lane the website deliberately does not absorb.', ], doesNotClaim: [ 'Anonymous public distribution and marketing duties.', - 'Protected billing or plan management.', - 'A finished VR or controller-rebinding lane beyond the current bounded keyboard, mouse, and settings ownership.', + 'Billing or plan management.', + 'A fully finished cross-device VR/controller lane beyond the current bounded keyboard, mouse, and settings ownership.', ], - nextStep: 'Use this surface for actual simulator execution, desktop training, package proof, and serious higher-dimensional work.', + nextStep: 'Use this when it is time to actually train, review a solve, or open the deeper puzzle families.', }, { title: 'Optional full-browser simulator branch', posture: 'Future branch', - description: 'This is a deliberately separate future branch whose existence stays visible so the current shipped topology is not misread.', + description: 'This is a deliberately separate future branch so the current product is never misread.', owns: [ - 'A documented future possibility only after a separate backend and runtime contract is deliberately reopened.', + 'A documented future possibility only after a separate runtime and backend contract is deliberately reopened.', 'Planning material that keeps the browser-client lane disciplined instead of vague.', - 'A clear boundary against accidental marketing overclaim.', + 'A clear boundary against accidental overclaim.', ], doesNotClaim: [ 'Current shipping simulator truth.', - 'Entitlement to displace the desktop-first runtime model.', + 'Permission to displace the current desktop-first model.', 'Any current production browser parity for higher-dimensional execution.', ], - nextStep: 'Keep it visible as a future branch, but do not route current users toward it as if it already ships.', + nextStep: 'Keep it visible as a future branch, but do not send today’s users there as if it already exists.', }, ] satisfies readonly ProductSurfaceMatrixRow[] export const featureRegistryTierCards = [ { - title: 'Implemented now', - description: 'This is current product truth and is safe to describe as live capability on public pages.', + title: 'Available today', + description: 'These are live product features and it is safe to describe them as available now on public pages.', bullets: [ 'Use this tier for the desktop runtime, browser dashboard, release status, and shipped higher-dimensional lanes.', - 'These are the surfaces operators can actually rely on today.', + 'These are the experiences players, teams, and buyers can actually rely on today.', 'Public copy should treat this tier as present, not aspirational.', ], }, { - title: 'Retained and planned', - description: 'This is real planned capability, but not something the public site should describe as already available.', + title: 'Coming next', + description: 'These are real planned capabilities, but not something the public site should describe as already available.', bullets: [ 'Use this tier for real product direction that still needs first-party release evidence.', - 'Public wording can describe it as retained, planned, or deliberately deferred.', - 'It should never be blurred into current live simulator truth.', + 'Public wording can describe it as planned, upcoming, or deliberately deferred.', + 'It should never be blurred into live simulator capability.', ], }, { - title: 'Future or internal-only branch', - description: 'This is a future decision path that remains intentionally outside current product claims.', + title: 'Future branch', + description: 'These are future decision paths that remain intentionally outside current product claims.', bullets: [ 'Use this tier for optional full-browser simulator or renderer-widening branches that remain outside the current product.', - 'Keep the branch visible so advanced users understand the boundary.', + 'Keep the branch visible so advanced users understand the difference.', 'Do not market these paths as available until they are deliberately reopened and revalidated.', ], }, @@ -255,134 +255,134 @@ export const featureRegistryTierCards = [ export const featureAtlasCurrentTracks = [ { title: 'Native training and coaching core', - description: 'The simulator itself is already first-party owned and lives in the desktop Unreal runtime.', + description: 'The heart of HyperTwist is the desktop simulator: fast, focused, and built for repeat practice.', bullets: [ - 'Native Unreal training runtime, coaching cockpit, and generated-mode launch are current product truth.', - 'Classic-cube timing, drill flows, and integrated training-session orchestration are already live.', - 'The desktop lane is where practice, runtime behavior, and serious execution quality are measured.', + 'Native Unreal training, coaching panels, and the guided first-run launch flow are already part of the product.', + 'Classic-cube timing, drill sessions, and repeatable practice loops are already live.', + 'This is the place HyperTwist is designed to feel fast, focused, and worth coming back to.', ], }, { - title: 'Recognition, replay, and operator diagnostics', - description: 'HyperTwist already treats recognition and analysis as operational product surfaces rather than vague future intent.', + title: 'Recognition, replay, and progress review', + description: 'HyperTwist already turns analysis into something you can actually use after a solve.', bullets: [ 'Browser-assisted recognition, correction closure, and solve-guidance readout are already shipped.', - 'Replay, analytics, local leaderboard persistence, and operator diagnostics are already part of the live training lane.', - 'The browser shell helps operators monitor and reach those surfaces without claiming browser simulator parity.', + 'Replay, analytics, local leaderboards, and native diagnostics are already part of the live training lane.', + 'The website helps you reach these tools cleanly, but the actual analysis and review still happen in the desktop app.', ], }, { title: 'Higher-dimensional and topology ownership', - description: 'Serious higher-dimensional work is part of the current product, not just background aspiration.', + description: 'Serious higher-dimensional study is already part of the product, not a teaser for later.', bullets: [ 'Dedicated Magic120Cell and MagicCube5D packaged runtime-state, projection, and persistence ownership are already live.', - 'MagicTile currently ships through the embedded browser host with state-bridge and native behavior-proof support.', - 'Renderer widening and generic browser parity remain explicitly reserved for later validation rather than being hand-waved away.', + 'MagicTile already ships through the in-app browser host with state-bridge and native behavior proof.', + 'Any future renderer widening or full browser edition remains clearly separate until it is genuinely ready.', ], }, { - title: 'Browser account, release, and distribution shell', - description: 'The website is part of the product because it owns access, release, pricing, legal, and rollout work the simulator should not absorb.', + title: 'Website account, release, and distribution shell', + description: 'The website is part of the product because it makes access, guidance, releases, and billing easy without turning the simulator into a storefront.', bullets: [ - 'Shared auth, billing status, protected download access, desktop-link pairing, and launch-readiness status already ship.', - 'Public docs, pricing, notices, and release surfaces are deliberate operator/distribution tools, not brochure-only pages.', - 'The public site is honest about desktop-first simulator truth while still being production-useful on its own terms.', + 'Shared auth, billing status, private download access, desktop-link pairing, and launch-readiness status already ship.', + 'Public docs, pricing, legal pages, and release surfaces are deliberate product tools, not brochure filler.', + 'The public site stays genuinely useful while keeping the desktop app as the main training surface.', ], }, ] as const export const advancedOperatorAdjunctTracks = [ { - title: 'Speech, voice, and capture adjuncts', - description: 'HyperTwist already owns bounded speech capture and narration families around the simulator instead of leaving all voice work as future intent.', + title: 'Speech, voice, and capture companions', + description: 'HyperTwist already includes voice-aware companion systems that make longer training sessions and review work richer.', bullets: [ 'Live microphone capture, permission/readiness workflows, and native capture-route control already ship in bounded first-party form.', - 'Downloadable speech-model custody, transcript envelopes, faster-whisper orchestration, local narration, and advanced voice-model review all exist as operator-facing adjunct surfaces.', - 'These are support-plane and runtime-adjacent capabilities; they do not change the desktop-first simulator authority.', + 'Downloadable speech-model custody, transcript envelopes, faster-whisper orchestration, local narration, and advanced voice-model review already exist as companion features.', + 'These deepen the training routine without changing the desktop-first simulator boundary.', ], }, { title: 'Provider routing, BYOK, and usage governance', - description: 'The product already includes provider-neutral AI or service governance instead of assuming one hidden backend forever.', + description: 'The product already includes serious service and provider controls instead of assuming one hidden backend forever.', bullets: [ 'Provider-neutral speech and vision contracts, BYOK/profile custody, custom-endpoint routing, and workflow-policy surfaces are already implemented.', - 'Usage/cost dashboards, history/export, receipt review, settlement, and exception handoff already exist as operator-facing governance shells.', - 'This keeps external-service status inspectable without pretending browser billing or auth is the same thing as simulator execution.', + 'Usage and cost dashboards, history/export, receipt review, settlement, and exception handoff already exist as first-party management surfaces.', + 'This keeps external-service status inspectable without confusing account work with simulator execution.', ], }, { title: 'Continuity, memory, and provenance', - description: 'HyperTwist also ships continuity-oriented surfaces that keep replay, training, and publication state from collapsing into stateless sessions.', + description: 'HyperTwist also ships continuity-oriented surfaces so your work can accumulate instead of vanishing between sessions.', bullets: [ 'Session continuity, workspace recall, chronicle, notes, knowledge, and derived memory families are already in the live feature registry.', - 'Provenance-aware replay or publication state plus ledger-style continuity and control-plane telemetry are part of the owned reference model.', - 'These families support serious operator and study workflows around the simulator rather than replacing the simulator itself.', + 'Provenance-aware replay or publication state plus ledger-style continuity are part of the owned reference model.', + 'These families support serious study and coaching workflows around the simulator rather than replacing it.', ], }, ] as const export const shippingNowCards = [ - 'Native Unreal training runtime, coaching cockpit, and generated-mode launch', - 'Classic-cube timing, drill flows, local leaderboard persistence, and replay recording', - 'Browser-assisted recognition shell with correction closure and recommendation readout', - 'Embedded browser runtime with live operator/runtime diagnostics inside Unreal', - 'MagicTile browser host bridge plus bounded native behavior proof', - 'Higher-dimensional 120-cell and 5D runtime-state, projection, and persistence ownership', - 'Speech capture, narration, and downloadable model-custody adjuncts', - 'Provider-neutral routing, usage governance, and continuity or provenance support surfaces', + 'A native Unreal simulator with a guided launch menu, coaching surfaces, and a real daily practice flow', + 'Classic-cube timing, drills, local leaderboards, and replay recording', + 'Recognition-assisted reconstruction with correction and solve guidance', + 'An in-app browser companion for live status, pairing, and focused web-powered tools', + 'MagicTile with its current desktop-hosted browser runtime and native behavior proof', + 'Dedicated 120‑cell and 5D runtime ownership with projection and persistence controls', + 'Speech capture, narration, and downloadable speech-model support', + 'Continuity, notes, and workflow support around the simulator', ] as const export const roadmapHonestyCards = [ - 'The embedded browser shell ships inside the desktop product. A standalone full-browser simulator remains a future branch, not today\'s training surface.', - 'MagicTile currently uses the embedded browser host; native renderer widening will only return if the shipped host stops meeting product needs.', - 'Pricing and checkout are Paddle-ready; public package delivery remains account-gated so subscription, notices, and source-disclosure duties stay attached.', - 'Desktop distribution is the primary product lane. Browser access is for account, operator, release, and support surfaces unless a later browser-client product branch is deliberately opened.', + 'The website is a polished companion experience, not a pretend replacement for the simulator. The deepest training still lives in the desktop app.', + 'MagicTile currently runs through the embedded browser host inside the desktop app, and that stays true until a stronger native path is truly ready.', + 'Pricing and checkout stay tied to account-backed delivery so subscriptions, notices, and source links remain clear.', + 'Desktop distribution is still the main product model. The website handles account access, release updates, support, and download handoff.', ] as const export const operatorManualTracks = [ { - title: '1. Start in the browser shell', - description: 'Begin with public pages and the protected dashboard so account, plan, and release status are resolved before any desktop rollout.', + title: '1. Start on the website', + description: 'Begin with the public site so your account, plan, and release status are clear before you install anything.', steps: [ - 'Review the current launch-status banner and release status.', - 'Create or sign in to a HyperTwist account.', - 'Use the dashboard to confirm plan, billing, and download entitlement state.', + 'Review the current launch status, release notes, and plan options.', + 'Create or sign in to your HyperTwist account.', + 'Use the dashboard to confirm your plan, billing, and download access.', ], }, { - title: '2. Move into the protected release lane', - description: 'The public site explains targets, but the actual entitled build stays in the protected download surface.', + title: '2. Open the signed-in download path', + description: 'The public site explains the release, while the actual build stays in the signed-in download area.', steps: [ 'Choose the target platform from the public download page.', - 'Preserve that platform hint through the sign-in boundary.', - 'Download the entitled package from the protected dashboard once access is resolved.', + 'Carry that platform choice through sign-in.', + 'Download the package once your account access is resolved.', ], }, { title: '3. Pair the installed desktop runtime', - description: 'Browser identity and desktop runtime are joined through a bounded desktop-link handshake instead of password reuse.', + description: 'Your website account and desktop app connect through a desktop-link handoff instead of password reuse.', steps: [ 'Generate a desktop-link token inside the dashboard.', 'Open the installed desktop runtime and verify through the token handoff.', - 'Keep release notes and notices visible during first rollout.', + 'Keep release notes and the first-run guide close at hand during the first launch.', ], }, { title: '4. Use the simulator for real training', - description: 'Classic-cube practice, replay, diagnostics, and higher-dimensional runtime ownership all live in the desktop lane.', + description: 'Classic-cube practice, replay, diagnostics, and higher-dimensional study all live in the desktop app.', steps: [ - 'Use the desktop runtime for recognition, replay, and coaching flows.', - 'Treat higher-dimensional training as a packaged native lane, not a browser claim.', - 'Use package proof and release notes to confirm the exact build state you are running.', + 'Use the desktop runtime for recognition, replay, coaching, and guided practice.', + 'Treat higher-dimensional training as a native desktop experience, not a browser claim.', + 'Use release notes and package proof to confirm the exact build you are running.', ], }, { - title: '5. Revisit browser surfaces for rollout governance', - description: 'Return to the website when you need operator status, support, launch readiness, or legal/distribution guidance.', + title: '5. Return to the website when needed', + description: 'Come back to the website when you need support, launch updates, billing, or another download.', steps: [ - 'Use the dashboard for auth, billing, and launch-readiness review.', - 'Use pricing, notices, and support pages for commercial/distribution status.', - 'Use docs and resources pages for public-safe explanations of the shipped lanes.', + 'Use the dashboard for account, billing, and launch-readiness review.', + 'Use pricing, legal, and support pages for purchase and distribution questions.', + 'Use docs and resources pages for clear explanations of what ships today.', ], }, ] as const @@ -390,47 +390,47 @@ export const operatorManualTracks = [ export const desktopWorkflowTracks = [ { title: '1. Run a classic-cube training session', - description: 'Use the desktop runtime when the goal is actual practice, not product orientation.', + description: 'Use the desktop app when the goal is real practice, not product orientation.', steps: [ - 'Launch the classic-cube training lane from the installed desktop runtime and confirm the HUD, timer, and scramble state first.', - 'Use the shipped classic control lane for turns, orbit, zoom, hint, fresh-attempt restart, and hold-to-talk behavior during the solve.', - 'Treat this as the authoritative packaged practice loop rather than trying to reproduce it through the public website.', + 'Launch the classic-cube training experience from the installed desktop app and confirm the HUD, timer, and scramble state first.', + 'Use the shipped classic control setup for turns, orbit, zoom, hint, fresh-attempt restart, and hold-to-talk behavior during the solve.', + 'Treat this as the real packaged practice loop rather than trying to reproduce it through the public website.', ], }, { title: '2. Run a recognition and correction workflow', - description: 'Use the desktop runtime when you need the real cube-state intake, correction, and solve-guidance lane.', + description: 'Use the desktop app when you need the real cube-state intake, correction, and solve-guidance flow.', steps: [ - 'Calibrate and observe the cube through the bounded classic-cube recognition workflow in the native runtime.', - 'Use the browser-assisted recognition shell, then resolve any manual corrections and accepted closure steps from the native training lane.', - 'Read the reconstruction and solve-guidance output as desktop workflow truth, not as a claim that the public website itself performs the recognition job.', + 'Calibrate and observe the cube through the bounded classic-cube recognition workflow in the desktop app.', + 'Use the browser-assisted recognition helper, then resolve any manual corrections and accepted closure steps inside the native training flow.', + 'Read the reconstruction and solve-guidance output as desktop-app truth, not as a claim that the public website itself performs the recognition job.', ], }, { title: '3. Review replay, coaching, and analytics', - description: 'Use the packaged desktop lane when the session needs replay continuity, coaching review, and outcome evidence in one place.', + description: 'Use the packaged desktop app when the session needs replay continuity, coaching review, and outcome evidence in one place.', steps: [ - 'Finish or import the training session, then open replay, coaching, and leaderboard or diagnostics surfaces inside the desktop runtime.', - 'Use the current native analytics and review surfaces to inspect timing, progression, and coaching output before escalating or exporting anything outward.', - 'Return to the browser shell only when account, release, entitlement, or support status becomes the next real concern.', + 'Finish or import the training session, then open replay, coaching, and leaderboard or diagnostics surfaces inside the desktop app.', + 'Use the current analytics and review surfaces to inspect timing, progression, and coaching output before escalating or exporting anything outward.', + 'Return to the website only when account, release, entitlement, or support status becomes the next real concern.', ], }, { - title: '4. Open the higher-dimensional family lanes', + title: '4. Open the higher-dimensional families', description: 'Use the packaged dedicated-family maps when training moves beyond the classic cube.', steps: [ - 'Launch the dedicated Magic120Cell or MagicCube5D map from the desktop runtime instead of expecting a browser parity lane.', - 'Use the shipped selector, focus, projection, symmetry or stereo, and visibility settings that the native operator surfaces already own explicitly.', + 'Launch the dedicated Magic120Cell or MagicCube5D map from the desktop app instead of expecting browser parity.', + 'Use the shipped selector, focus, projection, symmetry or stereo, and visibility settings that the native surfaces already own explicitly.', 'Use selector recall when a valid generated-mode launch history exists, while treating broader XR and controller rollout as a future device-proof step.', ], }, { - title: '5. Return to the browser shell for operator governance', - description: 'Use the browser shell after or around sessions when the next job is commercial, operational, or release-facing rather than simulator-facing.', + title: '5. Return to the website when the session is over', + description: 'Use the website after or around sessions when the next job is commercial, account-related, or release-facing rather than simulator-facing.', steps: [ - 'Use the protected dashboard for plan, entitlement, browser-to-desktop pairing, and release-manifest review.', - 'Use public or protected launch-status, notices, pricing, and release-notes routes when rollout, legal, or distribution status changes.', - 'Keep browser access issues separate from native runtime issues so support and rollout work stay attached to the correct surface.', + 'Use the signed-in dashboard for plan, access, website-to-desktop pairing, and release-manifest review.', + 'Use public or signed-in launch-status, notices, pricing, and release-notes pages when rollout, legal, or distribution status changes.', + 'Keep website access issues separate from desktop-app issues so support and rollout work stay attached to the correct surface.', ], }, ] as const @@ -438,36 +438,36 @@ export const desktopWorkflowTracks = [ export const operatorDesktopQuickstartCards = [ { title: '1. Resolve access and choose the right build', - description: 'The browser shell should settle identity, entitlement, release status, and target platform before the simulator ever launches.', + description: 'The website should settle identity, access, release status, and target platform before the simulator ever launches.', bullets: [ - 'Use the public download surface to choose the target platform and review package proof before install.', - 'Preserve that target through sign-in and confirm protected download entitlement in the dashboard.', - 'Treat launch status, release notes, and notices as part of the install decision rather than as later paperwork.', + 'Use the public download page to choose your target platform and review package proof before install.', + 'Preserve that target through sign-in and confirm private download access in the dashboard.', + 'Treat launch status, release notes, and legal details as part of the install decision rather than later paperwork.', ], }, { title: '2. Pair the installed runtime without password reuse', - description: 'HyperTwist keeps browser identity narrow and hands it to the desktop app through a bounded desktop-link token.', + description: 'HyperTwist keeps website identity narrow and hands it to the desktop app through a desktop-link token.', bullets: [ - 'Generate a desktop-link token from the protected dashboard after sign-in succeeds.', - 'Use the token during first launch so the installed runtime inherits the correct account and release status.', - 'Return to the browser shell later when account, plan, or release state changes.', + 'Generate a desktop-link token from the signed-in dashboard after sign-in succeeds.', + 'Use the token during first launch so the installed app inherits the correct account and release status.', + 'Return to the website later when account, plan, or release state changes.', ], }, { - title: '3. Verify the first native training lane', + title: '3. Verify the first native training session', description: 'The first serious simulator check should confirm classic-cube execution, replay, coaching, and the shipped control roster.', bullets: [ - 'Open the classic-cube lane and confirm timing, replay, guidance, and desktop HUD behavior.', + 'Open the classic-cube experience and confirm timing, replay, guidance, and desktop HUD behavior.', 'Use the shipped classic profile `classic-wca-keyboard/v1` together with click, touch, orbit, zoom, hint, and hold-to-talk behavior.', - 'Treat the public and protected browser shell as coordination surfaces around this runtime, not as substitutes for it.', + 'Treat the public and signed-in website surfaces as coordination layers around the app, not as substitutes for it.', ], }, { - title: '4. Open the higher-dimensional lanes and read the control boundary honestly', - description: 'The native desktop runtime already owns real 120-cell and 5D execution, but it still keeps XR/controller widening behind an explicit boundary.', + title: '4. Open the higher-dimensional families and read the control boundary honestly', + description: 'The native desktop app already owns real 120‑cell and 5D execution, but it still keeps broader XR and controller rollout behind an explicit boundary.', bullets: [ - 'Launch the dedicated `Magic120Cell` and `MagicCube5D` training maps from the packaged runtime.', + 'Launch the dedicated `Magic120Cell` and `MagicCube5D` training maps from the packaged app.', 'Use the current projection, focus, visibility, selector, and persisted selector-recall ownership as the current first-party settings model.', 'Do not mistake project-level controller groundwork for finished headset rollout; that branch still needs packaged device validation.', ], @@ -507,16 +507,16 @@ export const degradedStateRecoveryTracks = [ export const simulatorManualCards = [ { title: 'Classic-cube recognition and correction', - description: 'Use the desktop runtime when you need the actual recognition-to-reconstruction lane instead of public-site explanation.', + description: 'Use the desktop runtime when you want the real recognition-to-reconstruction flow instead of just reading about it.', bullets: [ 'Calibrate and observe the cube through the bounded classic-cube capture workflow.', 'Use browser-assisted recognition, manual correction closure, and solve-guidance readout from the native training lane.', - 'Treat this as an owned desktop workflow, not as a claim that the public website performs the reconstruction job itself.', + 'Treat this as a desktop training workflow, not a claim that the public website performs the reconstruction job itself.', ], }, { title: 'Replay, coaching, and analytics', - description: 'Use the desktop runtime when practice needs timing, leaderboard, replay, and coaching continuity in one place.', + description: 'Use the desktop runtime when practice needs timing, replay, coaching, and progress review in one place.', bullets: [ 'Run drill and timing sessions, then review replay and coaching outputs inside the native training surface.', 'Use the local leaderboard and diagnostics surfaces as part of the packaged runtime, not as detached web widgets.', @@ -527,7 +527,7 @@ export const simulatorManualCards = [ title: 'Higher-dimensional runtime ownership', description: 'Use the packaged Unreal maps for the serious hypercubing lane.', bullets: [ - 'Launch the dedicated-family 120-cell and 5D training maps from the desktop runtime.', + 'Launch the dedicated-family 120‑cell and 5D training maps from the desktop runtime.', 'Use the bounded visible-slice and projection ownership already landed for higher-dimensional exploration.', 'Keep the public website language honest: it can describe this lane, but it does not replace the packaged runtime that executes it.', ], @@ -546,29 +546,29 @@ export const simulatorManualCards = [ export const higherDimensionalRuntimeGuideCards = [ { title: 'Magic120Cell packaged runtime', - description: 'Use the packaged native training lane when you need real 120-cell runtime-state, projection ownership, and persistence-aware family behavior.', + description: 'Use the packaged native training lane when you want real 120‑cell space to study, rotate, and learn inside a serious simulator.', bullets: [ 'Launch the dedicated Magic120Cell training map from the desktop runtime.', 'Use the current symmetry, focus, and logical-visibility settings as the authoritative first-party runtime owner.', - 'The native operator and training surfaces now also expose the dedicated session surface, interactive-scene surface, persistence boundary, and family-owned state semantics for this lane explicitly.', - 'The native operator/training surfaces can now also recall the latest persisted generated-mode selector state for this family instead of hiding it behind the browser shell.', - 'Treat the public website as documentation and rollout support, not as the runtime that executes this family.', + 'The native training surfaces also expose the dedicated session, scene, persistence, and family-state semantics for this lane explicitly.', + 'The same native surfaces can recall the latest persisted generated-mode selector state for this family when it exists.', + 'Treat the public website as documentation and launch support, not as the runtime that executes this family.', ], }, { title: 'MagicCube5D packaged runtime', - description: 'Use the packaged native training lane when you need real 5D projection, stereo, focus, and face-visibility ownership.', + description: 'Use the packaged native training lane when you want real 5D projection, stereo, focus, and face-visibility study.', bullets: [ 'Launch the dedicated MagicCube5D training map from the desktop runtime.', 'Use the current projection-distance, stereo, and visibility defaults as the bounded first-party runtime settings.', - 'The native operator and training surfaces now also expose the dedicated session surface, interactive-scene surface, persistence boundary, and family-owned state semantics for this lane explicitly.', - 'The native operator/training surfaces can now also recall the latest persisted generated-mode selector state for this family instead of forcing a blind restart.', + 'The native training surfaces also expose the dedicated session, scene, persistence, and family-state seams for this lane explicitly.', + 'The same native surfaces can recall the latest persisted generated-mode selector state for this family instead of forcing a blind restart.', 'Keep this lane described honestly as packaged native behavior rather than browser simulator parity.', ], }, { title: 'MagicTile embedded-browser runtime', - description: 'Use the embedded browser lane for the current non-Euclidean tiling host while native renderer widening remains a future product decision.', + description: 'Use the embedded browser lane for the current non-Euclidean tiling host while deeper renderer expansion remains a future product decision.', bullets: [ 'Treat the embedded browser/CEF shell as the current shipped host for the live MagicTile interaction lane.', 'Keep shared scramble normalization, timer transport, and state-bridge ownership attached to the first-party native shell and bridge.', @@ -900,7 +900,7 @@ export const termsBoundaryCards = [ export const digitalDeliveryCards = [ { title: 'Release selection before install', - description: 'Digital delivery begins in the browser shell so the operator can review platform, entitlement, and release status before opening the desktop runtime.', + description: 'Digital delivery begins on the website so you can review platform, account access, and release status before opening the desktop app.', bullets: [ 'Choose the platform from the public download surface.', 'Carry that selection into the protected dashboard.', @@ -908,148 +908,148 @@ export const digitalDeliveryCards = [ ], }, { - title: 'Protected entitlement handoff', - description: 'The protected browser lane exists so digital delivery can stay account-aware without putting raw distribution logic on anonymous public pages.', + title: 'Private download handoff', + description: 'The signed-in website keeps private downloads tied to your account without placing sensitive delivery links on anonymous public pages.', bullets: [ - 'Use account state to gate the real package handoff.', + 'Use account state to unlock the real package handoff.', 'Use desktop-link pairing to hand identity over to the installed app.', - 'Keep public pages informative while preserving protected release access.', + 'Keep public pages informative while preserving private release access.', ], }, { - title: 'Post-install operator workflow', - description: 'Digital delivery is only complete when the installed runtime and the operator-facing browser shell remain aligned.', + title: 'After-install rhythm', + description: 'Delivery is only complete when the installed app and your website account stay aligned.', bullets: [ - 'Use the browser dashboard for account, billing, and rollout governance.', + 'Use the website dashboard for account, billing, and release guidance.', 'Use the desktop app for simulator execution, diagnostics, and higher-dimensional training.', - 'Return to notices, pricing, and support pages when release/compliance status changes.', + 'Return to notices, pricing, and support pages when release or compliance status changes.', ], }, ] as const export const resourceCollections = [ { - title: 'Product truth', + title: 'What HyperTwist really includes', items: [ - 'Feature registry-backed descriptions only', - 'Dedicated browser guide for the public web-version-versus-downloadable boundary', - 'Dedicated getting-started route for the first real browser-to-desktop operator journey', - 'Dedicated launch-status route for the canonical early-access and public-launch status surface', - 'Dedicated help-center route for product-safe onboarding and troubleshooting', - 'Public feature atlas for the real browser-versus-desktop product split', - 'Roadmap-honest separation between shipped and retained capability', - 'Release notes that surface what actually landed', - 'Desktop-first simulator model with browser-shell boundaries kept explicit', - 'Practical software-workflow manual for classic-cube, recognition, replay, and higher-dimensional use', - 'Public manual now surfaces the live speech, provider, and continuity adjunct families too', + 'A full tour of what is live right now', + 'A clear website-versus-desktop guide', + 'A real first-session path from first visit to first solve', + 'A launch-status page for early access and wider rollout visibility', + 'A help center for setup, controls, and troubleshooting', + 'A feature atlas for puzzle depth, training workflows, and account access', + 'Clear separation between what ships now and what is still in validation', + 'Release notes that explain what changed in plain language', + 'A desktop-first simulator model with a polished website companion', + 'Practical guides for classic cubes, replay, recognition, and higher-dimensional study', + 'Manual coverage for voice, provider, and continuity companion systems', ], }, { - title: 'Operator rollout', + title: 'Download and release', items: [ 'Desktop download instructions and release channels', - 'Desktop-link handshake for browser-to-desktop sign-in', - 'Legal/notices linkage for public distribution surfaces', - 'Package validation proof and release-readiness interpretation', + 'Desktop-link handoff for website-to-desktop sign-in', + 'Legal notices and source-link guidance for public distribution', + 'Build verification proof and release-readiness guidance', ], }, { title: 'Training depth', items: [ 'Classic-cube recognition and correction workflows', - 'Step-by-step desktop workflow guidance for practice, review, and higher-dimensional sessions', - 'Replay, coaching, analytics, and package validation status', - 'Higher-dimensional puzzle-family references and browser-host boundaries', - '120-cell and 5D dedicated-family runtime ownership overview', - 'Speech capture, narration, and model-custody adjunct status', + 'Step-by-step desktop workflows for practice, review, and higher-dimensional sessions', + 'Replay, coaching, analytics, and build-readiness updates', + 'Higher-dimensional family overviews and where each experience lives today', + '120‑cell and 5D family overviews', + 'Speech capture, narration, and downloadable-model status', ], }, { - title: 'Operator adjuncts', + title: 'Advanced companion systems', items: [ - 'Provider-neutral routing, BYOK/profile custody, and custom-endpoint status', - 'Usage or cost dashboards, export history, receipts, settlement, and exception handoff', - 'Continuity, memory, notes, and provenance-aware replay or publication state', - 'Operator-safe reference surfaces around the simulator instead of generic AI-platform claims', + 'Bring-your-own-key routing, profile custody, and custom-endpoint status', + 'Usage and cost dashboards, export history, receipts, settlement, and exception handoff', + 'Continuity, notes, memory, and provenance-aware replay or publication state', + 'Companion systems that deepen the simulator instead of distracting from it', ], }, { title: 'Deployment readiness', items: [ - 'Shared auth and browser-to-desktop pairing status', - 'Package validation proof and release-manifest interpretation', + 'Shared sign-in and website-to-desktop pairing status', + 'Build verification proof and release-manifest interpretation', 'Pricing, checkout, notices, and corresponding-source coordination', - 'Launch-readiness distinction between early-access, protected, and public lanes', + 'Launch-readiness distinctions between early access, signed-in access, and wider public rollout', ], }, { title: 'Recovery and escalation', items: [ - 'Auth recovery and mixed-mode guidance', - 'Release-authority recovery without raw package-delivery overclaim', - 'Direct contact route for operator, rollout, pricing, and legal follow-through questions', - 'Account, package, runtime, and compliance issue separation', - 'Operator-safe next steps when browser authority is degraded', + 'Sign-in recovery and mixed-mode guidance', + 'Release-status recovery without exposing private package delivery', + 'Direct contact routes for access, rollout, pricing, and legal follow-through', + 'Account, build, app, and compliance issue separation', + 'Clear next steps when website services are temporarily degraded', ], }, ] as const export const browserPurposeCards = [ { - title: 'Use the browser for access, release, and rollout status', - description: 'The browser lane owns the work that should stay inspectable outside the simulator.', + title: 'Use the website for access, updates, and your account', + description: 'The website is at its best when the job is discovery, account access, release updates, or buying and downloading the app.', bullets: [ - 'Open public pages for product research, pricing, release notes, legal notices, and launch-readiness status.', - 'Use the protected browser dashboard for sign-in, entitlement, billing, protected downloads, and desktop-link pairing.', - 'Keep rollout, purchase, and legal-follow-through work on the web so the simulator is not forced to become a storefront or auth shell.', + 'Open the public pages for product story, pricing, release notes, legal details, and launch status.', + 'Use the signed-in dashboard for plan access, billing, private downloads, and desktop-link pairing.', + 'Keep buying, account, and legal follow-through on the website so the simulator never has to become a storefront or login screen.', ], }, { - title: 'Use the browser for product-safe guidance and onboarding', - description: 'The web version is strong when the job is explanation, orientation, or operator coordination rather than simulator execution.', + title: 'Use the website for guidance and onboarding', + description: 'The web experience shines when the job is explanation, orientation, or team coordination rather than live puzzle play.', bullets: [ - 'Use the public docs, help, resources, and support routes as the current operator manual and rollout guide.', - 'Review first-launch guidance, control truth, package proof, and support lanes before deeper deployment or training work.', - 'Use the browser shell when a studio or buyer needs to understand what is real today without opening the native runtime first.', + 'Use docs, help, resources, and support as your manual and getting-started guide.', + 'Review first-launch guidance, control expectations, build proof, and support routes before deeper training work.', + 'Use the website when a buyer, coach, teacher, or team needs to understand what is real today without opening the desktop app first.', ], }, { - title: 'Use the browser after install when account state changes', - description: 'The browser remains part of the product after the desktop runtime is installed, but for bounded reasons.', + title: 'Come back to the website after install when account state changes', + description: 'The website remains part of the product after install, but for very specific reasons.', bullets: [ - 'Return to the browser for account changes, plan changes, desktop-link refresh, protected notices, release-manifest review, and support escalation.', - 'Keep browser issues separated from native runtime issues so support can diagnose the correct surface quickly.', - 'Treat the browser as the operator and distribution shell around the downloadable simulator, not as a hidden second simulator.', + 'Return to the website for account changes, plan changes, desktop-link refresh, private notices, release-manifest review, and support escalation.', + 'Keep website issues separated from desktop-app issues so support can diagnose the right surface quickly.', + 'Treat the website as the account and delivery layer around the simulator, not as a hidden second simulator.', ], }, ] as const export const browserLimitCards = [ { - title: 'What the browser version does not currently do', - description: 'The web lane is intentionally narrower and materially less powerful for the core simulator job.', + title: 'What still belongs to the desktop app', + description: 'The website is intentionally narrower because the richest parts of HyperTwist need the native downloadable.', bullets: [ - 'It does not own package-validated training behavior, replay execution, or the higher-dimensional packaged family maps.', - 'It does not own low-latency native input, device/runtime integration, or the dedicated Unreal session and scene surfaces that power the downloadable.', - 'It does not own packaged controller validation or the broader finished XR/controller branch; the bounded OpenXR runtime and controller-settings ownership stay native-only.', + 'It does not run the full simulator, the replay room, or the dedicated higher-dimensional family maps.', + 'It does not offer the same low-latency input, device access, or deep Unreal behavior that powers the desktop app.', + 'It does not yet claim finished packaged controller support or a complete XR experience; that work stays on the native side for now.', ], }, { - title: 'Why the downloadable is the primary product', - description: 'The downloadable stays primary because that is where the serious simulator work actually lives.', + title: 'Why the desktop app is where HyperTwist comes alive', + description: 'The desktop app stays primary because that is where practice starts to feel rich, responsive, and worth returning to every day.', bullets: [ - 'The desktop runtime owns recognition, correction closure, replay, coaching, analytics, and genuine session continuity.', - 'It owns the current dedicated `Magic120Cell` and `MagicCube5D` runtime-state, projection, persistence, and training-map execution lanes.', - 'It is also the current authority for packaged proof, native diagnostics, control roster truth, and serious study sessions.', + 'The desktop app owns recognition, correction, replay, coaching, analytics, and genuine session continuity.', + 'It owns the current dedicated `Magic120Cell` and `MagicCube5D` experiences, including projection, persistence, and packaged training-map execution.', + 'It is also where build proof, native diagnostics, control truth, and serious study sessions are easiest to trust.', ], }, { - title: 'When browser-only use is still worthwhile', - description: 'The website is not superfluous just because it is narrower.', + title: 'When the website is exactly the right tool', + description: 'The website stays valuable because it helps you choose, unlock, and support the product without making you install first.', bullets: [ - 'Use it for product evaluation, account access, protected release status, billing, notices, help, and launch-readiness review.', - 'Use it when a team needs product-safe explanation, public references, or rollout coordination without opening the simulator.', - 'Use it as the bounded bridge into the desktop runtime rather than as a lesser substitute for the simulator itself.', + 'Use it for product evaluation, account access, signed-in release status, billing, legal pages, help, and launch-readiness review.', + 'Use it when a team needs a clear explanation, public references, or rollout coordination without opening the simulator.', + 'Use it as the clean bridge into the desktop app rather than as a lesser substitute for the simulator itself.', ], }, ] as const @@ -1057,29 +1057,29 @@ export const browserLimitCards = [ export const browserWorkflowTracks = [ { title: '1. Start on the web before you install anything', - description: 'The first job is understanding release status and choosing the right operator path.', + description: 'The first job is understanding release status and choosing the right path into the product.', steps: [ 'Review launch status, pricing, and download guidance on the public site.', - 'Open docs, help, or resources if the team still needs rollout-safe explanation of the product topology.', - 'Choose the correct platform and plan status before you cross into the protected browser shell.', + 'Open docs, help, or resources if you want the product story, controls, or puzzle lineup explained before install.', + 'Choose the right platform and plan status before you move into your signed-in account area.', ], }, { - title: '2. Use the protected browser shell for account-aware follow-through', - description: 'The browser becomes stronger after sign-in, but still stays bounded to account and release work.', + title: '2. Use the signed-in website for account-aware follow-through', + description: 'The website becomes stronger after sign-in, but it still stays focused on account, download, and release work.', steps: [ - 'Sign in, review account and entitlement status, and generate a desktop-link token when needed.', - 'Use protected downloads and notices instead of expecting anonymous public pages to expose raw delivery authority.', - 'Keep the browser focused on release, billing, pairing, and rollout status rather than simulator execution.', + 'Sign in, review account and access status, and generate a desktop-link token when needed.', + 'Use private downloads and legal details instead of expecting anonymous public pages to expose raw delivery links.', + 'Keep the website focused on release, billing, pairing, and delivery status rather than simulator execution.', ], }, { title: '3. Hand off to the downloadable for the real simulator', - description: 'The browser flow succeeds when it leads cleanly into the desktop runtime instead of pretending to replace it.', + description: 'The website flow succeeds when it leads cleanly into the desktop app instead of pretending to replace it.', steps: [ - 'Install the package-validated desktop build and complete the bounded browser-to-desktop handoff.', - 'Use the desktop runtime for actual training, higher-dimensional work, replay, and diagnostics.', - 'Return to the browser later only when account, notices, rollout, or support context becomes the next real concern.', + 'Install the verified desktop build and complete the website-to-desktop handoff.', + 'Use the desktop app for actual training, higher-dimensional work, replay, and diagnostics.', + 'Return to the website later only when account, legal, release, or support context becomes the next real concern.', ], }, ] as const @@ -1087,56 +1087,56 @@ export const browserWorkflowTracks = [ export const puzzleCatalogCards = [ { title: 'Classic-cube practice and timing', - description: 'The downloadable already owns the current day-to-day solving lane for serious training use.', + description: 'The desktop app already owns the day-to-day solving experience for serious training.', bullets: [ - 'Classic timer, scramble, hints, mode switching, voice shortcuts, and replay-aware practice already ship.', - 'The public control truth is literal today: the shipped `classic-wca-keyboard/v1` profile plus click/touch, orbit, zoom, hint, and hold-to-talk behavior.', - 'This is the fastest way to verify that a fresh install matches the current public product story.', + 'Classic timing, scramble flow, hints, mode switching, voice shortcuts, and replay-aware practice already ship.', + 'The current control story is concrete today: the shipped `classic-wca-keyboard/v1` profile plus click or touch, orbit, zoom, hint, and hold-to-talk behavior.', + 'This is the fastest way to feel that a fresh install matches the promise of the website.', ], }, { title: 'Recognition, reconstruction, and solve guidance', - description: 'HyperTwist already treats physical-cube intake and correction closure as real first-party product work.', + description: 'HyperTwist already turns physical-cube intake and correction into a real first-party workflow.', bullets: [ - 'Use the desktop runtime for bounded capture, browser-assisted recognition, manual correction closure, and solve-guidance readout.', - 'The browser shell helps operators reach this workflow, but the actual reconstruction authority stays in the native runtime.', + 'Use the desktop app for capture, browser-assisted recognition, manual correction, and solve-guidance readout.', + 'The website helps you reach this workflow, but the actual reconstruction work stays inside the desktop app.', 'This keeps physical practice and analytical follow-through inside one coherent training system.', ], }, { title: 'Replay, coaching, and analytics', - description: 'The downloadable also owns session review, training continuity, and operator-facing evidence.', + description: 'The downloadable also owns session review, training continuity, and evidence-rich feedback.', bullets: [ - 'Replay capture, coaching review, local leaderboard persistence, diagnostics, and operator evidence already ship.', - 'These surfaces are part of the native runtime, not detached browser widgets pretending to be simulator parity.', - 'This is one of the clearest reasons the downloadable remains much more powerful than the web lane.', + 'Replay capture, coaching review, local leaderboard persistence, and diagnostics already ship.', + 'These tools live inside the desktop app, not in detached browser widgets pretending to be full simulator parity.', + 'This is one of the clearest reasons the downloadable remains much more powerful than the web experience.', ], }, { title: 'Magic120Cell packaged runtime', - description: 'HyperTwist already owns a real dedicated higher-dimensional family lane in the downloadable.', + description: 'HyperTwist already ships a real dedicated higher-dimensional family inside the downloadable.', bullets: [ - 'The desktop runtime owns live `Magic120Cell` session surfaces, scene surfaces, symmetry/focus settings, and persisted selector continuity.', - 'Operators can inspect session, interactive-scene, persistence-boundary, and state-semantics ownership directly in native diagnostics.', - 'This lane is described on the public site, but it is only executed in the downloadable runtime.', + 'The desktop app owns live `Magic120Cell` scenes, symmetry and focus settings, and saved selector continuity.', + 'Players and coaches can inspect the current scene, session, and persistence details directly in native diagnostics.', + 'This experience is described on the public site, but it is only executed in the downloadable app.', ], }, { title: 'MagicCube5D packaged runtime', - description: 'The downloadable already carries real 5D runtime ownership instead of just broad capability claims.', + description: 'The downloadable already carries real 5D depth instead of broad capability claims.', bullets: [ - 'Use the dedicated `MagicCube5D` map for projection-distance, stereo, focus, and face-visibility study inside the native runtime.', - 'Native diagnostics already expose the owning session, interactive-scene, persistence, and state-semantics seams for this family too.', - 'The browser can document and coordinate this lane, but it does not replace the downloadable that executes it.', + 'Use the dedicated `MagicCube5D` map for projection distance, stereo, focus, and face-visibility study inside the desktop app.', + 'Native diagnostics already expose the current scene, session, and persistence details for this family too.', + 'The website can document and coordinate this experience, but it does not replace the downloadable that executes it.', ], }, { - title: 'MagicTile embedded-browser lane', - description: 'HyperTwist also carries a bounded non-Euclidean lane, but it is still intentionally hosted inside the desktop product.', + title: 'MagicTile inside the desktop app', + description: 'HyperTwist also carries a non-Euclidean experience, and it is intentionally hosted inside the desktop product.', bullets: [ - 'The current live `MagicTile` lane runs through the embedded browser host inside Unreal rather than through the public website.', + 'The current live `MagicTile` experience runs through the embedded browser host inside Unreal rather than through the public website.', 'State bridge, scramble normalization, and timer continuity are already first-party owned around that host.', - 'Native renderer widening remains an explicit gate, so the public product story stays honest about where this lane currently lives.', + 'A deeper native renderer path remains a future decision, so the public product story stays honest about where this experience currently lives.', ], }, ] as const @@ -1160,7 +1160,7 @@ export const audienceFitCards = [ }, { title: 'Hypercubers and topology-focused learners', - description: 'HyperTwist is already unusual in that it treats higher-dimensional work as a real shipping lane.', + description: 'HyperTwist is already unusual in that it treats higher-dimensional work as a real shipping experience.', bullets: [ 'Dedicated `Magic120Cell`, `MagicCube5D`, and bounded `MagicTile` lanes are public, truthful, and source-backed today.', 'The downloadable remains essential here because the higher-dimensional runtime ownership is not a browser claim.', @@ -1168,21 +1168,21 @@ export const audienceFitCards = [ }, { title: 'Studios, educators, and rollout owners', - description: 'The website matters most for teams that need distribution, launch, and support status before training sessions begin.', + description: 'The website matters most for teams that need distribution, launch, and support clarity before training sessions begin.', bullets: [ - 'Pricing, notices, support, launch status, docs, help, and browser-to-desktop handoff are deliberate operator surfaces.', - 'This is the strongest reason the browser lane is still worth keeping even though the downloadable remains the main product.', + 'Pricing, notices, support, launch status, docs, help, and browser-to-desktop handoff all matter before a team adopts the software.', + 'This is one of the strongest reasons the browser experience is still worth keeping even though the desktop app remains the main product.', ], }, ] as const export const helpCenterCards = [ { - title: 'Account, access, and protected downloads', - description: 'Use the help center when the next task is getting into the right browser or release lane safely.', + title: 'Account, access, and private downloads', + description: 'Use the help center when the next task is getting into the right account area or download path safely.', bullets: [ - 'Choose the right public route, preserve the requested platform through sign-in, and use the protected dashboard for entitlement-aware delivery.', - 'Keep sign-in, release, and desktop-link questions attached to the browser shell instead of flattening them into simulator bugs.', + 'Choose the right public route, preserve the requested platform through sign-in, and use the signed-in dashboard for account-aware delivery.', + 'Keep sign-in, release, and desktop-link questions attached to the website instead of flattening them into simulator bugs.', ], }, { @@ -1198,42 +1198,42 @@ export const helpCenterCards = [ description: 'The current input story is strong, but it is bounded and should be taught honestly.', bullets: [ 'Keyboard, mouse, touch, camera, immersive settings, selector continuity, and dedicated-family view ownership are already real.', - 'Broader headset/controller rollout waits for Windows packaged controller proof on the shipping lane; bounded runtime owners plus first-party controller settings/rebinding already exist underneath that gate.', + 'Broader headset and controller rollout still waits for packaged Windows proof; the underlying OpenXR groundwork and first-party controller settings are already there, but the final claim is intentionally held back.', ], }, { - title: 'Rollout, pricing, notices, and release follow-through', - description: 'Help is not only for runtime bugs. It is also for distribution-safe operation.', + title: 'Launch, pricing, notices, and release details', + description: 'Help is not only for app bugs. It is also for clean digital delivery.', bullets: [ - 'Use pricing, launch status, notices, and corresponding-source guidance together when a team is evaluating public rollout.', - 'Keep commercial, legal, release, and simulator questions separated so operators can move faster with less confusion.', + 'Use pricing, launch status, legal pages, and source-availability guidance together when a team is evaluating a release.', + 'Keep commercial, legal, release, and simulator questions separated so people can move faster with less confusion.', ], }, ] as const export const contactChannelCards = [ { - title: 'Operator support', - description: 'Use this when a real user session is blocked by account, entitlement, or rollout issues.', + title: 'Account and access support', + description: 'Use this when a real user session is blocked by account, plan, or release-access issues.', bullets: [ - `Contact ${brandConfig.contact.email} for access, release enablement, desktop-link pairing trouble, or protected browser-lane follow-through.`, - 'Include the exact route, plan status, requested platform, and whether the failure is public, protected, or native.', + `Contact ${brandConfig.contact.email} for access, release enablement, desktop-link pairing trouble, or signed-in website follow-through.`, + 'Include the exact route, plan status, requested platform, and whether the problem is public, signed-in, or inside the desktop app.', ], }, { - title: 'Runtime issue reporting', + title: 'Desktop app issue reporting', description: 'Use this when the downloadable itself behaves unexpectedly.', bullets: [ - 'Name the affected lane: classic cube, recognition, replay/coaching, `Magic120Cell`, `MagicCube5D`, or `MagicTile`.', - 'Include build/channel context, control state, and whether the issue is a real shipped regression or a still-explicit unfinished headset/controller expectation.', + 'Name the affected experience: classic cube, recognition, replay or coaching, `Magic120Cell`, `MagicCube5D`, or `MagicTile`.', + 'Include build or channel context, control state, and whether the issue is a real shipped regression or an unfinished headset or controller expectation.', ], }, { - title: 'Studio rollout and commercial contact', - description: 'Use this when the question is deployment, pricing, or broader rollout readiness rather than one operator session.', + title: 'Studio and commercial contact', + description: 'Use this when the question is deployment, pricing, or broader team readiness rather than one person’s session.', bullets: [ - 'Bundle plan, platform, launch status, notices, and release expectations together so commercial follow-through stays attached to real package and legal truth.', - 'Use this lane for production-oriented training programs, deployment review, and release-safe distribution planning.', + 'Bundle plan, platform, launch status, legal details, and release expectations together so commercial follow-through stays attached to real package truth.', + 'Use this lane for training programs, deployment review, and release-safe distribution planning.', ], }, ] as const @@ -1246,36 +1246,36 @@ export const publicManualRouteAtlasCards = [ bullets: [ 'Summarizes what HyperTwist already ships today.', 'Shows live public launch-readiness and packaged-proof context.', - 'Points operators toward getting started, pricing, download, and the protected dashboard without overclaiming browser parity.', + 'Points people toward getting started, pricing, downloads, and the signed-in dashboard without overclaiming browser parity.', ], }, { title: 'Browser access guide', route: '/browser', - description: 'Open this route when you need the cleanest public explanation of what the web version is for, why it is intentionally narrower, and when to move into the downloadable.', + description: 'Open this route when you want the clearest public explanation of what the website is great at, what the desktop app adds, and when to move into the downloadable.', bullets: [ - 'Explains the browser shell as a real operator/distribution surface instead of a half-promised simulator.', - 'Shows what the browser version does well, what it deliberately does not do, and why the downloadable remains the primary product.', + 'Explains the website as a real account, support, and delivery hub instead of a half-promised simulator.', + 'Shows what the website does well, what the desktop app adds, and why the downloadable remains the primary product.', 'Keeps account, protected dashboard, and desktop handoff decisions visible in one place.', ], }, { title: 'Feature atlas', route: '/features', - description: 'Open this page when you need capability truth instead of pitch language.', + description: 'Open this page when you need a concrete feature map instead of vague pitch language.', bullets: [ 'Separates implemented now, retained, and future validation branches.', - 'Maps public website, protected dashboard, embedded browser shell, native runtime, and optional browser-client scope.', - 'Surfaces higher-dimensional, control-roster, and release-maturity truth in one place.', + 'Maps the public website, signed-in dashboard, embedded browser tools, desktop app, and optional future browser-client scope.', + 'Surfaces higher-dimensional depth, control choices, and release maturity in one place.', ], }, { title: 'About', route: '/about', - description: 'Use this route when you want the product rationale and the higher-dimensional seriousness explained in operator-grade language.', + description: 'Use this route when you want the product rationale and the higher-dimensional ambition explained in plain language.', bullets: [ 'Frames why HyperTwist keeps both browser and desktop surfaces.', - 'Explains the real end-to-end session story instead of flattening the topology.', + 'Explains the real end-to-end session story instead of flattening the product into one vague promise.', 'Keeps current control, XR, and release-maturity truth attached to the narrative.', ], }, @@ -1437,7 +1437,7 @@ export const releasePacketCards = [ version: 'Public manual deepening packet', category: 'Website, onboarding, and operator documentation', notes: [ - 'Broadened the public and offline operator manual so the website now explains concrete desktop workflows, controls, higher-dimensional families, and release follow-through instead of only broad topology prose.', + 'Broadened the public and offline manual so the website now explains concrete desktop workflows, controls, higher-dimensional families, and release details instead of only broad topology prose.', 'Made the browser-versus-desktop split explicit on the highest-traffic public routes so teams no longer have to infer why the downloadable remains the primary simulator.', 'Kept the current XR/controller boundary visible while strengthening what the public site can honestly claim today.', ], @@ -1497,58 +1497,58 @@ export const releasePacketCards = [ export const changelogEntries = [ { date: 'July 2, 2026', - title: 'Browser login shell now has explicit overlay-safety proof before live deploy', - details: 'Login and registration keep the decorative auth backdrop, but the auth shell now owns a higher stacking layer so production users do not see an opaque overlay over the form. The responsive public-route suite now verifies the auth shell sits above the same-origin auth backdrop, and the main-branch CI path now follows validation with the same-origin live-deploy helper so pushed website fixes can reach hypertwist.app through the supported production chain.', + title: 'Login and sign-up now stay clean and readable during load', + details: 'The website login and registration experience now keeps its decorative backdrop safely behind the form, so people no longer hit an opaque overlay while trying to sign in or create an account. The deploy path was also tightened so validated website fixes can reach hypertwist.app through the supported production chain instead of stalling at source only.', }, { date: 'June 30, 2026', - title: 'Downloadable operator manual now mirrors the richer public manual routes', - details: 'The same-origin offline operator manual is no longer the thinner sibling of the live website. It now mirrors the richer public/manual lane with browser-auth status, protected release handoff, concrete desktop workflow tracks, the shipped control roster, higher-dimensional family guidance, operator adjunct families, recovery guidance, and a public/protected route atlas so rollout teams can carry one substantial offline reference without inventing a second product story.', + title: 'The offline desktop guide now feels like the real manual', + details: 'The downloadable guide is no longer the thinner sibling of the website. It now mirrors the richer public manual with sign-in guidance, desktop handoff steps, concrete training workflows, the shipped control roster, higher-dimensional family guidance, recovery guidance, and a page-by-page route atlas so teams can carry one substantial reference with the app.', }, { date: 'June 30, 2026', - title: 'Homepage and About now answer the browser-versus-desktop boundary directly', - details: 'The highest-traffic public marketing routes no longer leave the web-versus-native question buried in deeper support copy alone. Homepage and About now surface the shared product-boundary FAQ directly, including why the browser lane stays narrower, why that is a strength instead of a weakness, and why the optional full-browser simulator branch still remains spec-only.', + title: 'Homepage and About now explain the website-versus-desktop split up front', + details: 'The highest-traffic public pages no longer bury the web-versus-desktop question in support copy. Home and About now say plainly why the website stays lighter, why that makes the product easier to trust, and why the downloadable remains the main place for real training.', }, { date: 'June 30, 2026', - title: 'Native control-settings diagnostics now distinguish absent versus partial higher-dimensional ownership', - details: 'The desktop training-panel and coach-dashboard settings diagnostics no longer flatten every degraded 120-cell, 5D, or selector lane into one vague partial label. The current operator-facing formatter now keeps absent versus partial versus ready ownership explicit while still preserving the ready-side profile, selector, and continuity facts that actually exist.', + title: 'Higher-dimensional settings readouts are now much clearer', + details: 'The desktop diagnostics no longer flatten degraded 120-cell, 5D, or selector states into one vague partial label. Higher-dimensional settings now show a clearer absent-versus-partial-versus-ready picture while still preserving the real profile, selector, and continuity facts that already exist.', }, { date: 'June 30, 2026', - title: 'Login and registration now explain the real desktop workflows too', - details: 'The public auth entry pages now keep a compact desktop-workflow overview beside the existing access and topology guidance, so operators can see the concrete classic-cube and recognition workflows they are signing in for before they ever cross into the protected browser shell.', + title: 'Login and sign-up now preview the real desktop experience', + details: 'The account-entry pages now place a compact desktop-workflow overview beside the existing access guidance, so people can see the classic-cube and recognition experiences they are signing in for before they even reach the dashboard.', }, { date: 'June 30, 2026', - title: 'Protected browser routes now teach the concrete desktop workflows too', - details: 'The signed-in dashboard, browser-access, download, and account routes now share a first-party protected workflow manual for classic-cube practice, recognition and correction, replay/coaching review, and higher-dimensional session use. Protected browser access now explains not only release and entitlement status, but also what the installed software is actually used for once the browser handoff is complete.', + title: 'The signed-in dashboard now teaches the software, not just the account state', + details: 'The signed-in dashboard, browser-access, download, and account routes now share a first-party workflow guide for classic-cube practice, recognition and correction, replay or coaching review, and higher-dimensional sessions. Signed-in access now explains not only release and account status, but also what the installed software is actually used for once the handoff is complete.', }, { date: 'June 30, 2026', - title: 'Public manual now teaches concrete desktop workflows across the main operator routes', - details: 'Home, About, Getting Started, Docs, and Resources now include first-party practical workflow cards for classic-cube training, recognition and correction, replay/coaching review, higher-dimensional session use, and browser-return governance. The public site no longer explains topology and readiness only; it now also teaches how the current software is actually used.', + title: 'The public manual now teaches real day-to-day workflows', + details: 'Home, About, Getting Started, Docs, and Resources now include practical workflow cards for classic-cube training, recognition and correction, replay or coaching review, higher-dimensional sessions, and the moments when it makes sense to come back to the website. The public site no longer explains release posture only; it now also teaches how the current software is actually used.', }, { date: 'June 29, 2026', - title: 'Public manual now surfaces shipped speech, provider, and continuity adjunct families', - details: 'The homepage, feature atlas, docs, and resources now stop flattening HyperTwist down to recognition plus hypercubing only. Public-facing product truth now also carries the already-live speech capture and narration lane, provider-neutral routing and usage-governance shells, and the continuity or provenance families that support serious operator workflows around the desktop simulator.', + title: 'The site now shows more of HyperTwist than cubes alone', + details: 'The homepage, feature atlas, docs, and resources now stop flattening HyperTwist down to recognition plus hypercubing only. Public-facing product truth now also includes speech capture and narration, provider routing and usage controls, and the continuity features that support longer-term study around the desktop simulator.', }, { date: 'June 29, 2026', - title: 'Fresh exact-state audit kept the owned toolchain and release surfaces green', - details: 'A same-day exact-state rerun reconfirmed the current HyperTwist production-hardening lane without widening scope: `sentrux gate` stayed flat at `Quality: 6234 -> 6234` with no degradation, the owned `sentrux` snapshot stayed green at `Quality: 6234`, the bounded GitNexus mirror refreshed cleanly to `16,406` nodes / `38,773` edges / `677` clusters / `300` flows while honestly falling back to `npx gitnexus@latest` on this Linux host, and the full web-surface umbrella passed again with `14` website files / `82` tests, `3` deployment-readiness files / `30` tests, `10` website-server files / `36` tests, successful website plus browser-runtime builds, and clean production audits except for the already-documented upstream `supertokens-node -> nodemailer` residual.', + title: 'The website and release toolchain were revalidated on current source', + details: 'A fresh exact-state audit reconfirmed the current HyperTwist hardening packet without widening scope. The source-health tools stayed green, the GitNexus mirror refreshed cleanly, and the full website, deployment-readiness, and website-server test umbrellas passed again together with successful website and browser-runtime builds.', }, { date: 'June 29, 2026', - title: 'Protected launch surfaces now name the concrete live access blockers too', - details: 'The signed-in dashboard and protected `/app/launch-status` lane now mirror the same concrete live blocker details already shown on the public launch surface. Instead of only generic setup prose, signed-in operators now see whether Windows release publication, operator/studio checkout, webhook secret, billing plan maps, shared-auth runtime readiness, or live runtime warnings are the actual remaining access blockers.', + title: 'Signed-in launch status now calls out the real blockers directly', + details: 'The signed-in dashboard and signed-in `/app/launch-status` page now mirror the same concrete live blockers shown on the public launch surface. Instead of generic setup prose, people can now see whether Windows publication, checkout readiness, webhook setup, billing mapping, shared-auth readiness, or live runtime warnings are the actual remaining blockers.', }, { date: 'June 29, 2026', - title: 'Responsive route proof and live early-access readiness were revalidated again', - details: 'The owned web-surface umbrella was rerun with responsive Playwright coverage, keeping all major public and protected routes clean on mobile and tablet while the same-origin readiness command also passed again against `https://hypertwist.app`. The current launch truth remains disciplined: the site is live and healthy in account-gated early access, while Windows download, Paddle checkout, webhook-secret, and loopback SuperTokens-core warnings still remain explicit instead of being blurred into a false public-launch claim.', + title: 'Responsive route coverage and live early-access readiness were rechecked', + details: 'The responsive Playwright coverage was rerun, keeping all major public and signed-in routes clean on mobile and tablet while same-origin readiness passed again against `https://hypertwist.app`. The launch story stays disciplined: the site is live in account-gated early access, while the remaining Windows download, checkout, webhook, and shared-auth warnings remain explicit instead of being blurred into a false full-public-launch claim.', }, { date: 'June 29, 2026', @@ -1623,12 +1623,12 @@ export const changelogEntries = [ { date: 'June 27, 2026', title: 'The remaining legal public routes now carry the same release-decision guide too', - details: 'Open-source notices, privacy, terms, and shipping/payment no longer stop at the lighter surface-choice handoff. They now also expose the same explicit next release move guidance as the rest of the operator-facing public site: protected desktop access, pricing/provisioning, protected browser/account continuity, or notices/source follow-through.', + details: 'Open-source notices, privacy, terms, and shipping/payment no longer stop at the lighter surface-choice handoff. They now also expose the same explicit next release move guidance as the rest of the public site: protected desktop access, pricing/provisioning, protected browser/account continuity, or notices and source details.', }, { date: 'June 25, 2026', title: 'Public pages now carry one shared release-reference bundle end to end', - details: 'Home, About, Features, Resources, Docs, Support, Changelog, Privacy, Terms, Pricing, Download, Notices, and Shipping/Payment now all keep the same direct docs, release-notes, corresponding-source, public-repository/notices, and operator-support references visible instead of fragmenting release follow-through by route.', + details: 'Home, About, Features, Resources, Docs, Support, Changelog, Privacy, Terms, Pricing, Download, Notices, and Shipping/Payment now all keep the same direct docs, release-notes, corresponding-source, public-repository/notices, and support references visible instead of fragmenting release details by route.', }, { date: 'June 25, 2026', @@ -1761,7 +1761,7 @@ export const releaseRolloutChecklist = [ { title: 'Read the actual lane that changed', bullets: [ - 'Differentiate native simulator/runtime work from browser-operator or release-surface work before changing rollout expectations.', + 'Differentiate native simulator/runtime work from browser or release-surface work before changing rollout expectations.', 'Treat selector-recall, control-profile, and diagnostics entries as native-surface truth, not as a claim that the browser lane now owns simulator behavior.', ], }, @@ -1769,7 +1769,7 @@ export const releaseRolloutChecklist = [ title: 'Confirm package proof before broad rollout', bullets: [ 'Pair the release note with the current packaged-validation summary so teams know whether a native change is merely implemented or also freshly package-proven.', - 'Use the protected download center when actual entitlement or package delivery status matters.', + 'Use the protected download center when actual access or package delivery status matters.', ], }, { @@ -1808,32 +1808,32 @@ export const sourceAvailability = { export const browserDesktopDecisionFaqs = [ { - question: 'Is the simulator fully in the browser?', - answer: 'No. The current shipping lane is desktop-first and Unreal-backed. The public website offers account, operator, support, and download access, while the optional full-browser simulator path remains spec-only, so the browser does not currently replace the package-validated native runtime.', + question: 'Can I use HyperTwist entirely in my browser?', + answer: 'Not today. The current shipping product is desktop-first and Unreal-backed. The website gives you account access, downloads, billing, support, and release guidance, but the real simulator still lives in the downloadable app.', }, { - question: 'If the desktop app is primary, why keep the web version?', - answer: 'Because the browser shell owns the parts that should stay outside the simulator: public positioning, account access, billing, release status, protected download access, notices, support-safe rollout guidance, and browser-to-desktop pairing. It is intentionally inferior for the core simulator job: it does not own package-validated training behavior, low-latency native input, higher-dimensional packaged execution, or device/runtime integration authority. That narrower boundary is a strength, not a weakness, because it keeps the native runtime easier to trust, easier to operate, and easier to ship honestly.', + question: 'What is the website actually for?', + answer: 'The website is where you create an account, manage billing, read release notes, get help, review notices, and unlock private downloads. It is intentionally lighter than the desktop app for the core simulator job, and that is a strength: it keeps the front door fast, clear, and easy to trust.', }, { - question: 'Is VR/controller support already fully finished?', - answer: 'Not yet. HyperTwist already has real classic keyboard and mouse or touch ownership, viewer camera and immersive settings ownership, higher-dimensional selector and view ownership, EnhancedInput setup, motion-controller groundwork, a bounded OpenXR runtime owner, and first-party controller settings/rebinding ownership. But the broader native OpenXR/controller lane still needs Windows packaged controller validation with controller truth before HyperTwist should market a finished headset/runtime branch.', + question: 'Is VR support already complete?', + answer: 'Not yet. HyperTwist already has real keyboard and mouse support, camera and immersive settings, higher-dimensional view controls, a bounded OpenXR foundation, and first-party controller settings and rebinding ownership. What still remains is packaged Windows controller validation before HyperTwist should market a finished headset branch.', }, ] export const supportFaqs = [ { question: 'Which browser sign-in methods are actually supported?', - answer: 'Email/password is the baseline shared-auth lane. GitHub, Google, and ORCID may also appear when the current deployment has those providers configured. Regardless of method, browser sign-in only opens the protected account, release, and desktop-pairing surfaces; it does not replace the native desktop simulator.', + answer: 'Email and password are the baseline. GitHub, Google, and ORCID may also appear when the current deployment has those providers configured. No matter which sign-in method you use, the website opens your account, release access, and desktop pairing tools; it does not replace the native desktop simulator.', }, ...browserDesktopDecisionFaqs, { question: 'Can I already customize controls and higher-dimensional view settings?', - answer: 'Partly. The current desktop runtime already owns the classic keyboard profile, viewer camera settings, bounded camera-export continuity, immersive-presence settings, session-local immersive recall, and higher-dimensional projection, focus, stereo, symmetry, and visibility defaults. The native operator surfaces now also expose which Magic120Cell or MagicCube5D session surface, interactive scene, persistence boundary, and state-semantics contract currently owns that settings lane, and they can recall selector state from the latest persisted generated-mode launch request. The bounded XR desktop lane now also owns first-party controller settings, layout presets, and rebinding truth for the exact shipped XR input ids. What remains outside the current shipping lane is Windows packaged controller proof and broader launch-tier XR completion.', + answer: 'Yes, in a meaningful but still bounded way. The current desktop app already owns the classic keyboard profile, camera settings, immersive settings, session-local recall, and higher-dimensional projection, focus, stereo, symmetry, and visibility defaults. It can also show which Magic120Cell or MagicCube5D session, scene, and persistence details own those settings, and it can recall selector state from the latest persisted generated-mode launch request. What still remains outside the current shipping scope is packaged Windows controller proof and broader XR completion.', }, { question: 'Do higher-dimensional selector choices persist between sessions?', - answer: 'They can now persist in a bounded way. When the desktop runtime has a structurally valid generated-mode launch request on hand, the native operator and training surfaces can recall that selector state. That is useful real continuity, but it is still narrower than a full global preferences or controller-rebinding system.', + answer: 'They can now persist in a bounded way. When the desktop app has a structurally valid generated-mode launch request on hand, the native training surfaces can recall that selector state. That is useful real continuity, but it is still narrower than a full global preferences or controller-rebinding system.', }, { question: 'Can I download a build immediately after sign-in?', @@ -1841,15 +1841,15 @@ export const supportFaqs = [ }, { question: 'Does HyperTwist already include voice or speech support?', - answer: 'Yes, in a bounded adjunct form. The live product already owns microphone capture, permission/readiness workflows, native capture-route control, transcript session envelopes, downloadable speech-model custody, Python transcription-service orchestration, local narration, and advanced voice-model review state. Those are real operator-facing support surfaces around the simulator, not a claim that the website itself becomes the training runtime.', + answer: 'Yes, in a bounded companion form. The live product already owns microphone capture, permission and readiness flows, native capture controls, transcript session envelopes, downloadable speech-model custody, transcription orchestration, local narration, and advanced voice-model review state. Those are real support systems around the simulator, not a claim that the website itself becomes the training runtime.', }, { question: 'Are provider routing and continuity features already real?', - answer: 'Yes, again in a bounded operator-grade form. HyperTwist already has provider-neutral speech or vision contracts, BYOK/profile custody, custom-endpoint routing, workflow-policy controls, usage/cost and settlement shells, plus continuity, memory, knowledge, notes, and provenance-aware replay or publication state families. These are adjunct governance and workflow surfaces around the simulator, not a claim that every external service is mandatory for core local training.', + answer: 'Yes, again in a bounded companion form. HyperTwist already has provider-neutral speech or vision contracts, BYOK and profile custody, custom-endpoint routing, workflow controls, usage and cost views, plus continuity, notes, memory, and provenance-aware replay or publication state families. These are support systems around the simulator, not a claim that every external service is mandatory for core local training.', }, { question: 'Why is there an open-source notices page on pricing and download surfaces?', - answer: 'Because HyperTwist already carries explicit doctrine requiring public legal and corresponding-source linkage whenever a downloadable shipped build contains MPL-covered material.', + answer: 'Because HyperTwist keeps legal notices and source links visible anywhere the product is sold or delivered. If a shipped desktop build contains MPL-covered material, those links belong right beside pricing and download access.', }, ] as const @@ -1929,7 +1929,7 @@ export const firstSessionVerificationCards = [ }, { title: 'Verify the higher-dimensional lane you plan to use', - description: 'The serious 120-cell and 5D families should be confirmed intentionally, not inferred from broad capability claims.', + description: 'The serious 120‑cell and 5D families should be confirmed intentionally, not inferred from broad capability claims.', bullets: [ 'Launch the dedicated `Magic120Cell` or `MagicCube5D` packaged training map from the desktop runtime instead of assuming browser parity.', 'Confirm the current selector, projection, focus, symmetry or stereo, and visibility settings you intend to use before treating the session as higher-dimensional-ready.', @@ -2032,10 +2032,10 @@ export const supportEscalationCards = [ ] as const export const companyNarrative = { - mission: 'HyperTwist closes the gap between physical cubing practice, deep replay analysis, operator-grade coaching, and serious higher-dimensional puzzle study.', + mission: 'HyperTwist closes the gap between physical cubing practice, deep replay analysis, guided coaching, and serious higher-dimensional puzzle study.', posture: - 'The product is intentionally honest about what already ships, what is planned, and what remains a future branch. That honesty is part of the platform quality bar.', + 'The product is intentionally honest about what already ships, what is still being validated, and what remains a future branch. That honesty is part of the quality bar.', distribution: - 'The website exists to support public positioning, authenticated operator access, pricing, notices, and desktop distribution without pretending the browser itself already replaces the real desktop runtime.', + 'The website exists to support discovery, account access, pricing, notices, and desktop delivery without pretending the browser already replaces the real simulator.', contactEmail: brandConfig.contact.email, } diff --git a/website/src/styles/global.css b/website/src/styles/global.css index 77e6b64..da5edb0 100644 --- a/website/src/styles/global.css +++ b/website/src/styles/global.css @@ -15,6 +15,22 @@ --ht-grid: rgba(148, 201, 255, 0.06); --font-display: "Space Grotesk", "IBM Plex Sans", sans-serif; --font-body: "IBM Plex Sans", system-ui, sans-serif; + --brand-logo-default-size: clamp(1.6rem, 1.95vw, 1.9rem); + --brand-logo-scale: 3.5; + --pui-grad-from: #48d7ff; + --pui-grad-mid: #3da8ff; + --pui-grad-to: #f7b267; + --pui-wave-text: #d9ecff; + --pui-wave-text-hover: #f5fbff; + --pui-wave-border: rgba(84, 203, 255, 0.28); + --pui-wave-border-hover: rgba(84, 203, 255, 0.44); + --pui-glow: 0 0 26px rgba(72, 215, 255, 0.22); + --pui-glow-strong: 0 0 52px rgba(72, 215, 255, 0.28), 0 0 96px rgba(247, 178, 103, 0.16); + --pui-button-dark-fill: linear-gradient(180deg, rgba(10, 18, 34, 0.96), rgba(8, 13, 24, 0.94)); + --pui-button-dark-popover-fill: linear-gradient(180deg, rgba(9, 16, 28, 0.98), rgba(7, 11, 20, 0.98)); + --pui-button-dark-border: rgba(84, 203, 255, 0.16); + --pui-shimmer-sweep: rgba(255, 255, 255, 0.34); + --pui-shimmer-sweep-edge: rgba(255, 255, 255, 0.1); } @property --glow-angle { @@ -50,6 +66,20 @@ html[data-theme="light"] { --ht-amber-soft: rgba(200, 104, 15, 0.12); --ht-success: #0f8b56; --ht-grid: rgba(35, 90, 167, 0.08); + --pui-grad-from: #0c8dd6; + --pui-grad-mid: #2f93f6; + --pui-grad-to: #d67a12; + --pui-wave-text: #164776; + --pui-wave-text-hover: #0b2445; + --pui-wave-border: rgba(32, 105, 184, 0.3); + --pui-wave-border-hover: rgba(32, 105, 184, 0.48); + --pui-glow: 0 0 24px rgba(32, 105, 184, 0.1); + --pui-glow-strong: 0 0 48px rgba(32, 105, 184, 0.14), 0 0 80px rgba(214, 122, 18, 0.1); + --pui-button-dark-fill: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(246, 250, 255, 0.96)); + --pui-button-dark-popover-fill: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(245, 249, 255, 0.98)); + --pui-button-dark-border: rgba(12, 86, 152, 0.14); + --pui-shimmer-sweep: rgba(6, 25, 49, 0.22); + --pui-shimmer-sweep-edge: rgba(6, 25, 49, 0.06); } * { @@ -96,14 +126,19 @@ img { .site-shell, .app-shell { min-height: 100vh; + position: relative; + isolation: isolate; } .site-header, -.page-main, -.site-footer, .app-topbar, .app-main { position: relative; +} + +.page-main, +.site-footer { + position: relative; z-index: 1; } @@ -119,35 +154,81 @@ img { radial-gradient(circle at top, rgba(84, 203, 255, 0.08), transparent 46%), linear-gradient(180deg, rgba(8, 12, 22, 0.82), rgba(10, 16, 30, 0.72)); position: sticky; - top: 0; + top: 0.75rem; + z-index: 9999; + isolation: isolate; + contain: paint; + overflow: clip; + backface-visibility: hidden; + transform: translateZ(0); margin: 0.75rem auto 0; width: min(1260px, calc(100vw - 2rem)); border-radius: 1.6rem; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 22px 60px rgba(0, 0, 0, 0.22); - transition: transform 220ms ease, opacity 220ms ease, border-color 220ms ease, box-shadow 220ms ease; + transition: transform 220ms ease, opacity 220ms ease, border-color 220ms ease, box-shadow 220ms ease, background 220ms ease; will-change: transform; } -.site-header--hidden { - transform: translateY(calc(-100% - 1.25rem)); - opacity: 0; +.site-header::before { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; pointer-events: none; + background: + linear-gradient(135deg, rgba(84, 203, 255, 0.18), transparent 30%), + linear-gradient(315deg, rgba(247, 178, 103, 0.16), transparent 34%); + opacity: 0.85; +} + +.site-header > * { + position: relative; + z-index: 1; +} + +.site-header--hidden { + transform: translate3d(0, calc(-100% - 3rem), 0) scale(0.985); + opacity: 0; + visibility: hidden; + pointer-events: none; + max-height: 0; + min-height: 0; + height: 0; + padding-top: 0; + padding-bottom: 0; + margin-top: 0; + border-width: 0; + clip-path: inset(0 0 100% 0 round 1.6rem); + backdrop-filter: none; + background: transparent; + border-color: transparent; + box-shadow: none; + overflow: hidden; + content-visibility: hidden; +} + +.site-header--hidden::before { + opacity: 0; } .brand-mark { display: flex; align-items: center; gap: 0.9rem; + flex: 1 1 24rem; min-width: 0; } .brand-mark__image { - width: clamp(6.5rem, 9vw, 9.72rem); - height: clamp(6.5rem, 9vw, 9.72rem); + width: calc(var(--brand-logo-default-size) * var(--brand-logo-scale)); + height: calc(var(--brand-logo-default-size) * var(--brand-logo-scale)); + min-width: 0; + flex: none; object-fit: contain; filter: drop-shadow(0 0 34px rgba(84, 203, 255, 0.3)); + max-width: none; } .app-sidebar__brand-image { @@ -159,7 +240,8 @@ img { .brand-mark__copy { display: grid; - gap: 0.2rem; + gap: 0.3rem; + min-width: 0; } .brand-mark strong, @@ -167,7 +249,7 @@ img { display: block; font-family: var(--font-display); letter-spacing: 0.02em; - font-size: clamp(1.35rem, 2vw, 1.7rem); + font-size: clamp(1.5rem, 2.35vw, 1.98rem); line-height: 0.96; } @@ -180,7 +262,7 @@ img { } .brand-mark small { - font-size: 0.98rem; + font-size: 1rem; max-width: 29rem; } @@ -200,12 +282,16 @@ img { } .site-nav { + flex: 1 1 26rem; flex-wrap: wrap; + align-items: center; justify-content: center; } .site-header__actions { + flex: 0 1 auto; flex-wrap: wrap; + align-items: center; justify-content: flex-end; } @@ -220,9 +306,11 @@ img { .site-nav__link, .app-nav__link { padding: 0.7rem 0.95rem; + border: 1px solid transparent; border-radius: 999px; color: var(--ht-muted); font-weight: 600; + background: rgba(255, 255, 255, 0.02); transition: 160ms ease; } @@ -231,6 +319,7 @@ img { .app-nav__link:hover, .app-nav__link.is-active { color: var(--ht-text); + border-color: var(--ht-border); background: var(--ht-cyan-soft); } @@ -238,48 +327,229 @@ img { display: inline-flex; align-items: center; justify-content: center; - gap: 0.5rem; - min-height: 2.8rem; - padding: 0.82rem 1.18rem; + position: relative; + overflow: hidden; + isolation: isolate; + gap: 0.58rem; + min-height: 3rem; + padding: 0.88rem 1.22rem; border-radius: 999px; border: 1px solid transparent; + font-family: var(--font-display); font-weight: 700; letter-spacing: 0.01em; + line-height: 1.1; cursor: pointer; transition: transform 160ms ease, background 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease; text-align: center; white-space: nowrap; + text-wrap: nowrap; +} + +.button::after { + content: ""; + position: absolute; + inset: 0; + z-index: 0; + border-radius: inherit; + background: linear-gradient(115deg, transparent 10%, rgba(255, 255, 255, 0.22) 42%, transparent 70%); + opacity: 0.55; + transform: translateX(-140%); + transition: transform 240ms ease; +} + +.button > * { + position: relative; + z-index: 1; } .button:hover { transform: translateY(-1px); } +.button:hover::after { + transform: translateX(120%); +} + .button.pui-btn { font-family: var(--font-body); + background: var(--pui-button-dark-fill); + border-color: var(--pui-button-dark-border); + box-shadow: + 0 16px 34px rgba(8, 14, 28, 0.22), + inset 0 1px 0 rgba(255, 255, 255, 0.06); +} + +.button.pui-btn > span { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.58rem; + white-space: nowrap; + line-height: 1.05; +} + +.button svg { + flex: none; + display: block; +} + +.button:hover { + transform: translateY(-1px); } .button--primary { - background: linear-gradient(120deg, var(--ht-amber), #ffc788); - color: #09111d; - border-color: rgba(247, 178, 103, 0.72); + color: var(--ht-text); + border-color: rgba(84, 203, 255, 0.18); box-shadow: - 0 14px 34px rgba(247, 178, 103, 0.24), - 0 0 0 1px rgba(255, 255, 255, 0.08) inset; + 0 18px 40px rgba(33, 121, 199, 0.18), + 0 0 0 1px rgba(255, 255, 255, 0.05) inset; } .button--ghost { - background: rgba(255, 255, 255, 0.04); + background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.03)); border-color: var(--ht-border); color: var(--ht-text); + backdrop-filter: blur(12px); } .button--secondary { + border-color: rgba(84, 203, 255, 0.3); color: var(--ht-text); + box-shadow: + 0 14px 30px rgba(84, 203, 255, 0.14), + 0 0 0 1px rgba(255, 255, 255, 0.04) inset; +} + +.button.pui-btn--glow { + color: var(--ht-text); + background: + radial-gradient(circle at var(--glow-x) var(--glow-y), rgba(84, 203, 255, 0.34), transparent 38%), + linear-gradient(135deg, rgba(76, 212, 255, 0.2), rgba(12, 20, 36, 0.96) 42%, rgba(247, 178, 103, 0.22)); + border-color: rgba(84, 203, 255, 0.28); + box-shadow: var(--pui-glow-strong), inset 0 1px 0 rgba(255, 255, 255, 0.08); + backdrop-filter: blur(14px) saturate(120%); +} + +.button.pui-btn--glow::before { + opacity: 0.72; + filter: blur(14px); +} + +.button.pui-btn--wave { + min-height: 3rem; + padding-top: 0.72rem; + padding-bottom: 0.78rem; + color: var(--pui-wave-text); + background: + linear-gradient(135deg, rgba(84, 203, 255, 0.18), rgba(9, 16, 28, 0.96) 42%, rgba(247, 178, 103, 0.18)), + linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0)); + border-color: var(--pui-wave-border); + box-shadow: + 0 14px 28px rgba(8, 14, 28, 0.18), + inset 0 1px 0 rgba(255, 255, 255, 0.06); +} + +.button.pui-btn--ghost:hover { + border-color: rgba(84, 203, 255, 0.32); +} + +html[data-theme="light"] .button--primary { + color: #081426; +} + +html[data-theme="light"] .button--ghost { + background: linear-gradient(180deg, rgba(255, 255, 255, 0.88), rgba(240, 247, 255, 0.9)); +} + +html[data-theme="light"] .button--secondary { + color: #093055; +} + +html[data-theme="light"] .button.pui-btn { + background: linear-gradient(180deg, rgba(255, 255, 255, 0.97), rgba(245, 249, 255, 0.98)); + border-color: rgba(18, 82, 145, 0.14); + box-shadow: + 0 18px 34px rgba(26, 78, 132, 0.08), + inset 0 1px 0 rgba(255, 255, 255, 0.88); +} + +html[data-theme="light"] .button.pui-btn--glow { + color: #081426; + background: + radial-gradient(circle at var(--glow-x) var(--glow-y), rgba(69, 178, 233, 0.28), transparent 40%), + linear-gradient(135deg, rgba(76, 197, 255, 0.24), rgba(255, 255, 255, 0.98) 42%, rgba(247, 178, 103, 0.22)); + border-color: rgba(24, 96, 165, 0.24); + box-shadow: + 0 24px 46px rgba(28, 92, 151, 0.12), + 0 0 40px rgba(96, 196, 245, 0.12); +} + +html[data-theme="light"] .button.pui-btn--wave { + color: #11355b; + background: + linear-gradient(135deg, rgba(82, 195, 248, 0.14), rgba(255, 255, 255, 0.98) 38%, rgba(247, 178, 103, 0.16)), + linear-gradient(180deg, rgba(255, 255, 255, 0.78), rgba(245, 249, 255, 0.94)); + border-color: rgba(26, 96, 164, 0.24); } .theme-toggle { - min-width: 6.2rem; + min-width: 7.15rem; + padding-inline: 0.95rem; +} + +.theme-toggle__content { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + line-height: 1; + white-space: nowrap; + width: auto; +} + +.theme-toggle__icon, +.theme-toggle__label { + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1; +} + +.theme-toggle__icon { + width: 1rem; + height: 1rem; + flex: none; +} + +.theme-toggle__icon svg { + width: 1rem; + height: 1rem; + display: block; +} + +.theme-toggle__label { + min-width: 0; + text-align: center; + white-space: nowrap; +} + +html[data-theme="light"] .theme-toggle__icon, +html[data-theme="light"] .theme-toggle__label { + color: #0d3d67; +} + +.page-main h1, +.page-main h2, +.page-main h3, +.page-main strong, +.page-main .eyebrow, +.metric-card strong, +.metric-card span, +.site-nav__link, +.button { + word-break: keep-all; + hyphens: none; } .button--full { @@ -341,6 +611,7 @@ img { font-family: var(--font-display); font-size: clamp(2.4rem, 6vw, 4.8rem); line-height: 0.98; + text-wrap: balance; } .page-hero__lede, @@ -353,8 +624,10 @@ img { .auth-card__subtitle { color: var(--ht-muted); line-height: 1.7; - overflow-wrap: anywhere; - word-break: break-word; + overflow-wrap: break-word; + word-break: normal; + text-wrap: pretty; + hyphens: none; } .page-hero__lede { @@ -707,14 +980,32 @@ img { .list li, .auth-card__footer { - overflow-wrap: anywhere; - word-break: break-word; + overflow-wrap: break-word; + word-break: normal; + text-wrap: pretty; + hyphens: none; +} + +.button-row .button.pui-btn { + align-items: center; +} + +.button-row .button.pui-btn > span { + min-width: 0; } .feature-band { flex-wrap: wrap; } +.no-break { + display: inline-block; + white-space: nowrap; + text-wrap: nowrap; + word-break: keep-all; + hyphens: none; +} + .feature-band__card { flex: 1 1 280px; display: block; @@ -726,6 +1017,88 @@ img { rgba(10, 16, 30, 0.56); } +html[data-theme="light"] .site-header { + border-color: rgba(20, 78, 136, 0.12); + background: + radial-gradient(circle at top, rgba(75, 194, 245, 0.14), transparent 44%), + radial-gradient(circle at 88% 16%, rgba(247, 178, 103, 0.12), transparent 32%), + linear-gradient(180deg, rgba(255, 255, 255, 0.94), rgba(244, 249, 255, 0.9)); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.82), + 0 20px 44px rgba(28, 88, 147, 0.12); +} + +html[data-theme="light"] .site-nav__link, +html[data-theme="light"] .app-nav__link { + background: rgba(17, 92, 163, 0.05); + color: #2f4f73; +} + +html[data-theme="light"] .site-nav__link:hover, +html[data-theme="light"] .site-nav__link.is-active, +html[data-theme="light"] .app-nav__link:hover, +html[data-theme="light"] .app-nav__link.is-active { + color: #0f2b48; + border-color: rgba(25, 95, 163, 0.16); + background: rgba(72, 181, 235, 0.12); +} + +html[data-theme="light"] .page-hero { + background: + radial-gradient(circle at top, rgba(76, 197, 255, 0.2), transparent 42%), + radial-gradient(circle at 82% 18%, rgba(247, 178, 103, 0.14), transparent 30%), + linear-gradient(180deg, rgba(255, 255, 255, 0.94), rgba(240, 246, 255, 0.96)); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.92), + 0 28px 72px rgba(28, 88, 147, 0.12); +} + +html[data-theme="light"] .hero-panel, +html[data-theme="light"] .page-section, +html[data-theme="light"] .site-footer, +html[data-theme="light"] .auth-card, +html[data-theme="light"] .app-sidebar, +html[data-theme="light"] .app-topbar, +html[data-theme="light"] .panel, +html[data-theme="light"] .hero-visual-card, +html[data-theme="light"] .metric-card, +html[data-theme="light"] .card, +html[data-theme="light"] .callout, +html[data-theme="light"] .timeline-entry { + border-color: rgba(20, 78, 136, 0.12); + background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(244, 249, 255, 0.96)); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.92), + 0 22px 54px rgba(28, 88, 147, 0.08); +} + +html[data-theme="light"] .hero-panel { + background: + radial-gradient(circle at top left, rgba(76, 197, 255, 0.14), transparent 34%), + radial-gradient(circle at bottom right, rgba(247, 178, 103, 0.12), transparent 30%), + linear-gradient(180deg, rgba(255, 255, 255, 0.97), rgba(243, 249, 255, 0.97)); +} + +html[data-theme="light"] .hero-visual-card, +html[data-theme="light"] .feature-band__card, +html[data-theme="light"] .metric-card { + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.94), rgba(239, 246, 255, 0.96)), + rgba(242, 248, 255, 0.96); + border-color: rgba(20, 78, 136, 0.12); +} + +html[data-theme="light"] .feature-band__card:hover, +html[data-theme="light"] .feature-band__card--link:hover, +html[data-theme="light"] .card:hover, +html[data-theme="light"] .callout:hover, +html[data-theme="light"] .timeline-entry:hover { + border-color: rgba(214, 122, 18, 0.28); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.92), + 0 24px 60px rgba(28, 88, 147, 0.12); +} + .feature-band__card--link { transition: border-color 160ms ease, transform 160ms ease; } @@ -824,11 +1197,13 @@ img { .auth-shell { min-height: 100vh; + width: 100%; position: relative; z-index: 1; isolation: isolate; - display: grid; - place-items: center; + display: flex; + align-items: center; + justify-content: center; padding: 1.25rem; } @@ -853,14 +1228,17 @@ img { } .auth-card { - width: min(760px, 100%); + width: 100%; + max-width: 760px; padding: 1.6rem; - display: grid; + display: flex; + flex-direction: column; gap: 1rem; } .auth-form { - display: grid; + display: flex; + flex-direction: column; gap: 0.7rem; } @@ -929,7 +1307,8 @@ img { } .provider-row { - display: grid; + display: flex; + flex-direction: column; gap: 0.7rem; } @@ -1197,8 +1576,8 @@ code { } .brand-mark__image { - width: 6.2rem; - height: 6.2rem; + width: 7rem; + height: 7rem; } .button-row > * { @@ -1211,6 +1590,12 @@ code { white-space: normal; } + .button-row .button.pui-btn > span, + .provider-row .button.pui-btn > span { + white-space: normal; + text-wrap: balance; + } + .product-reality-strip, .product-reality-strip--compact { grid-template-columns: 1fr; diff --git a/website/tests/e2e/responsive-public-pages.spec.ts b/website/tests/e2e/responsive-public-pages.spec.ts index a2173ec..a9f6a33 100644 --- a/website/tests/e2e/responsive-public-pages.spec.ts +++ b/website/tests/e2e/responsive-public-pages.spec.ts @@ -11,24 +11,24 @@ type PublicRouteExpectation = { const responsivePublicRoutes: readonly PublicRouteExpectation[] = [ { path: '/', - heading: 'From first solves to 120-cell, HyperTwist keeps the real simulator in the downloadable.', - cta: 'Download desktop app', + heading: 'One serious home for classic cubes, 120‑cell, 5D, and deep daily practice.', + cta: 'Create account', }, { path: '/features', - heading: 'Feature truth without the guesswork.', + heading: 'A deep training toolkit, not just a timer.', }, { path: '/about', - heading: 'A training stack serious enough for higher-dimensional cubing.', + heading: 'A training stack built for people who want more than a timer.', }, { path: '/resources', - heading: 'Resources that explain the product without leaking operator-only internals.', + heading: 'Every guide you need to start, train, and grow with HyperTwist.', }, { path: '/docs', - heading: 'HyperTwist documentation stays capability-accurate.', + heading: 'The complete HyperTwist manual.', }, { path: '/pricing', @@ -40,7 +40,7 @@ const responsivePublicRoutes: readonly PublicRouteExpectation[] = [ }, { path: '/getting-started', - heading: 'Start in the browser. Train in the desktop runtime.', + heading: 'Start on the website. Train in the desktop app.', }, { path: '/launch-status', @@ -48,7 +48,7 @@ const responsivePublicRoutes: readonly PublicRouteExpectation[] = [ }, { path: '/support', - heading: 'Support for rollout, downloads, pricing, and browser-to-desktop access.', + heading: 'Help for access, downloads, setup, and launch.', }, { path: '/login', @@ -57,7 +57,7 @@ const responsivePublicRoutes: readonly PublicRouteExpectation[] = [ }, { path: '/changelog', - heading: 'Release notes you can actually use for rollout.', + heading: 'Release notes for players, teams, and studios.', }, { path: '/open-source-notices',