Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/main-branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,10 @@ jobs:
- name: Install Playwright browsers
run: python -m playwright install --with-deps chromium

- name: Clean up Python bytecode
run: |
find . -type d -name "__pycache__" -exec rm -rf {} +
find . -name "*.pyc" -delete

- name: Run tests
run: pytest
72 changes: 48 additions & 24 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,53 +74,77 @@ <h2>What the lights mean</h2>
</div>

<ul id="dependency-list" class="dependency-list">
<li class="dependency-item" data-dependency="secure-context" data-state="pending">
<li
class="dependency-item"
data-dependency="secure-context"
data-state="pending"
data-pass-status="Ready — secure and private"
data-fail-status="Fix: Use HTTPS or localhost"
>
<div class="dependency-header">
<span class="dependency-name">Secure connection (HTTPS or localhost)</span>
<span class="dependency-status">Checking…</span>
</div>
<p class="dependency-instructions">
If this light is red: look at the address bar at the top. The link should start with <code>https://</code> or say
<code>localhost</code>. If it doesn’t, add the missing <code>https://</code> or open the site from our secure Unity AI Lab page.
It’s just like buckling a seatbelt so everything stays safe.
<p class="dependency-message" data-message-type="pass">
Secure connection detected. Unity can safely access the microphone and speech features.
</p>
<p class="dependency-message" data-message-type="fail">
Open this page with <code>https://</code> or from <code>localhost</code>, then press “Check again.”
</p>
<p class="dependency-reminder">After you fix it, press the big “Check again” button.</p>
</li>
<li class="dependency-item" data-dependency="speech-recognition" data-state="pending">
<li
class="dependency-item"
data-dependency="speech-recognition"
data-state="pending"
data-pass-status="Ready — Unity can listen"
data-fail-status="Fix: Switch to a supported browser"
>
<div class="dependency-header">
<span class="dependency-name">Web Speech Recognition API</span>
<span class="dependency-status">Checking…</span>
</div>
<p class="dependency-instructions">
If this light is red: your browser can’t hear you yet. Open this page in the latest version of Google Chrome,
Microsoft Edge, or another browser that supports talking and listening. Imagine switching to a friend who knows how
to play the game.
<p class="dependency-message" data-message-type="pass">
Speech recognition is available. Unity will understand what you say.
</p>
<p class="dependency-message" data-message-type="fail">
Open this page in the latest Chrome or Edge, then press “Check again.”
</p>
<p class="dependency-reminder">Switch browsers or update yours, then press “Check again.”</p>
</li>
<li class="dependency-item" data-dependency="speech-synthesis" data-state="pending">
<li
class="dependency-item"
data-dependency="speech-synthesis"
data-state="pending"
data-pass-status="Ready — Unity can speak back"
data-fail-status="Fix: Enable browser speech voices"
>
<div class="dependency-header">
<span class="dependency-name">Speech synthesis voices</span>
<span class="dependency-status">Checking…</span>
</div>
<p class="dependency-instructions">
If this light is red: the browser doesn’t know how to speak back. Make sure your speakers aren’t muted and that
you’re using a browser with voice support (Chrome, Edge, or Safari on desktop works best). Refresh the page after
turning the sound on.
<p class="dependency-message" data-message-type="pass">
Speech voices are ready. Unity can answer out loud through your speakers.
</p>
<p class="dependency-message" data-message-type="fail">
Use Chrome, Edge, or Safari with audio enabled, then press “Check again.”
</p>
<p class="dependency-reminder">When you’re ready, press “Check again” to retry.</p>
</li>
<li class="dependency-item" data-dependency="microphone" data-state="pending">
<li
class="dependency-item"
data-dependency="microphone"
data-state="pending"
data-pass-status="Ready — Microphone unlocked"
data-fail-status="Fix: Allow microphone access"
>
<div class="dependency-header">
<span class="dependency-name">Microphone access</span>
<span class="dependency-status">Checking…</span>
</div>
<p class="dependency-instructions">
If this light is red: the browser needs permission to hear you. Look for a pop-up asking to use your microphone and
click “Allow.” If you missed it, click the lock icon in the address bar and enable the microphone. It’s like giving a
friend permission to listen to your story.
<p class="dependency-message" data-message-type="pass">
Microphone permission granted. Unity can hear your voice input.
</p>
<p class="dependency-message" data-message-type="fail">
Click “Allow” on the microphone prompt or enable it in site settings, then press “Check again.”
</p>
<p class="dependency-reminder">Press “Check again” after allowing the microphone.</p>
</li>
</ul>
</div>
Expand Down
27 changes: 20 additions & 7 deletions landing.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ function formatDependencyList(items) {
return `${head} and ${tail}`;
}

function getDependencyStatuses(item) {
if (!item) {
return {
passStatus: 'Ready',
failStatus: 'Check settings'
};
}

const { passStatus = 'Ready', failStatus = 'Check settings' } = item.dataset;
return { passStatus, failStatus };
}

function setStatusMessage(message, tone = 'info') {
if (!statusMessage) {
return;
Expand Down Expand Up @@ -196,24 +208,25 @@ function updateDependencyUI(results, allMet, { announce = false, missing = [] }
return;
}

item.dataset.state = result.met ? 'pass' : 'warn';
item.dataset.state = result.met ? 'pass' : 'fail';
const statusElement = item.querySelector('.dependency-status');
if (statusElement) {
statusElement.textContent = result.met ? 'Ready' : 'Check settings';
const { passStatus, failStatus } = getDependencyStatuses(item);
statusElement.textContent = result.met ? passStatus : failStatus;
}
});
}

if (dependencyLight) {
dependencyLight.dataset.state = allMet ? 'pass' : 'warn';
dependencyLight.dataset.state = allMet ? 'pass' : 'fail';
const summary = formatDependencyList(missing);
dependencyLight.setAttribute(
'aria-label',
allMet
? 'All dependencies satisfied'
: summary
? `Compatibility mode enabled because ${summary} is unavailable`
: 'Compatibility mode enabled. Some requirements are missing'
? `Missing requirements: ${summary}`
: 'Missing one or more requirements'
);
}

Expand All @@ -223,8 +236,8 @@ function updateDependencyUI(results, allMet, { announce = false, missing = [] }
} else {
const summary = formatDependencyList(missing);
dependencySummary.textContent = summary
? `We spotted a few red lights (${summary}). Talk to Unity will still launch, but those features may be limited until they turn green.`
: 'We spotted a few red lights. Talk to Unity will still launch, but some features may be limited.';
? `Red lights: ${summary}. Follow the fix steps below, then press "Check again."`
: 'Red lights detected. Follow the fix steps below, then press "Check again."';
}
}

Expand Down
3 changes: 3 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[pytest]
testpaths = tests
norecursedirs = OLD*
26 changes: 13 additions & 13 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -322,14 +322,14 @@ body[data-app-state='experience'] #landing {
box-shadow: 0 0 0 2px rgba(26, 10, 0, 0.5), 0 12px 30px rgba(244, 114, 22, 0.32);
}

.dependency-light[data-state='warn'] {
background: linear-gradient(135deg, var(--accent-amber), #b45309);
box-shadow: 0 0 0 2px rgba(26, 10, 0, 0.55), 0 12px 30px rgba(244, 114, 22, 0.36);
.dependency-light[data-state='fail'] {
background: linear-gradient(135deg, var(--accent-red), #7f1d1d);
box-shadow: 0 0 0 2px rgba(40, 0, 0, 0.55), 0 12px 30px rgba(255, 62, 62, 0.38);
}

.dependency-item[data-state='warn'] .dependency-name::before {
background: linear-gradient(135deg, var(--accent-amber), #b45309);
box-shadow: 0 0 0 2px rgba(26, 10, 0, 0.55), 0 8px 22px rgba(244, 114, 22, 0.28);
.dependency-item[data-state='fail'] .dependency-name::before {
background: linear-gradient(135deg, var(--accent-red), #7f1d1d);
box-shadow: 0 0 0 2px rgba(40, 0, 0, 0.55), 0 8px 22px rgba(255, 62, 62, 0.28);
}

.dependency-light[data-state='pass'] {
Expand Down Expand Up @@ -396,11 +396,17 @@ body[data-app-state='experience'] #landing {
color: rgba(255, 210, 210, 0.78);
}

.dependency-instructions {
.dependency-message {
margin: 0 0 8px;
color: rgba(255, 225, 225, 0.82);
line-height: 1.7;
font-size: 0.98rem;
display: none;
}

.dependency-item[data-state='pass'] .dependency-message[data-message-type='pass'],
.dependency-item[data-state='fail'] .dependency-message[data-message-type='fail'] {
display: block;
}

.landing-actions {
Expand Down Expand Up @@ -821,9 +827,3 @@ body.no-js .mute-indicator {
scroll-behavior: auto !important;
}
}
.dependency-reminder {
margin: 0;
color: rgba(255, 200, 200, 0.75);
font-size: 0.9rem;
}

5 changes: 4 additions & 1 deletion tests/test_landing_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ def test_landing_page_structure():
assert statuses.count() == 4
for idx in range(statuses.count()):
status_text = statuses.nth(idx).inner_text().strip().lower()
assert status_text in {"checking…", "checking...", "ready", "check settings"}
normalized = status_text.replace("—", "-")
if normalized.startswith("checking"):
continue
assert normalized.startswith("ready") or normalized.startswith("fix")

launch_button = page.locator("#launch-app")
assert launch_button.inner_text().strip() == "Talk to Unity"
Expand Down