Skip to content

Commit 62fcfa3

Browse files
committed
fixes
1 parent d96b572 commit 62fcfa3

6 files changed

Lines changed: 37 additions & 38 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ Rule format:
8989
- TPS cue semantics must be visually represented across both the editor and live reader surfaces: emotions, delivery, voice, pace, energy, pauses or breath marks, pronunciation, phonetics, stress, staccato, legato, emphasis, highlight, aside, rhetorical, building, sarcasm, loud, soft, whisper, and related cues need visible affordances that help the user read intent without inspecting raw TPS tags.
9090
- TPS cue rendering work must start from an explicit design note that maps each supported TPS style to its reader/editor visual treatment, animation, and test expectation before implementation, so the product does not grow one-off cue styling.
9191
- TPS visual cue work must include end-to-end browser coverage and public README screenshots or screenshot-backed examples so users can see that the editor and prompter render the supported cue taxonomy, not only parse it internally.
92+
- README TPS cue documentation must show a visual example for every supported cue family and tag treatment, using isolated plain-text reader examples where one word or phrase carries the cue so the visible effect is obvious.
9293
- User-facing file transfer actions in the shell should use `Import` and `Export` wording instead of `Open Script` and `Save File`, because the app also has its own internal script/workspace structure.
9394
- File workflows must stay local-first inside PrompterOne: scripts need in-app autosave and an internal change-history path in the browser environment, not only external disk import/export actions.
9495
- Hotkey work must target PrompterOne’s own browser surfaces and settings inventory only; do not design around OBS commands or claim OBS integration paths that the product does not have.

src/PrompterOne.Shared/wwwroot/design/modules/reader/20-controls.css

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -533,14 +533,16 @@
533533
border-radius: 50%;
534534
background: var(--gold-12);
535535
}
536-
.rd-controls.rd-reading-active .rd-ctrl-play {
537-
background: rgba(196,160,96,.09);
536+
.rd-controls.rd-reading-active .rd-ctrl-play,
537+
.rd-controls[data-active="true"] .rd-ctrl-play {
538+
background: rgba(196,160,96,.08);
538539
}
539540
.rd-ctrl-play:hover {
540541
background: var(--gold-16);
541542
}
542-
.rd-controls.rd-reading-active .rd-ctrl-play:hover {
543-
background: rgba(196,160,96,.10);
543+
.rd-controls.rd-reading-active .rd-ctrl-play:hover,
544+
.rd-controls[data-active="true"] .rd-ctrl-play:hover {
545+
background: rgba(196,160,96,.09);
544546
}
545547

546548
.rd-ctrl-label {

tests/PrompterOne.Web.UITests.Reader/Learn/LearnFidelityTests.cs

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public sealed class LearnFidelityTests(StandaloneAppFixture fixture)
1212
private readonly record struct ContextGapMeasurement(double LeftGapPx, double RightGapPx);
1313
private readonly record struct ContextRailClipMeasurement(double LeftClipPx, double RightClipPx);
1414
private readonly record struct FocusWordSlackMeasurement(double SlackPx);
15+
private readonly record struct OrpDeltaMeasurement(double DeltaPx);
1516
private readonly record struct VisibleContextWordGapMeasurement(double LeftWordGapPx, double RightWordGapPx);
1617

1718
[Test]
@@ -25,16 +26,12 @@ public async Task LearnScreen_KeepsOrpLetterCenteredOnReferenceGuide()
2526
await Expect(page.GetByTestId(UiTestIds.Learn.Page))
2627
.ToBeVisibleAsync(new() { Timeout = BrowserTestConstants.Timing.ExtendedVisibleTimeoutMs });
2728
await Expect(page.GetByTestId(UiTestIds.Learn.WordOrp)).ToBeVisibleAsync();
28-
await WaitForLearnLayoutReadyAsync(page);
29-
30-
var initialDelta = await MeasureOrpDeltaAsync(page);
29+
var initialDelta = (await WaitForLearnLayoutReadyAsync(page)).DeltaPx;
3130
await Assert.That(initialDelta).IsBetween(0, 6);
3231

3332
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.Learn.PlayToggle));
3433
await page.WaitForTimeoutAsync(BrowserTestConstants.Timing.LearnPlaybackDelayMs);
35-
await WaitForLearnLayoutReadyAsync(page);
36-
37-
var playbackDelta = await MeasureOrpDeltaAsync(page);
34+
var playbackDelta = (await WaitForLearnLayoutReadyAsync(page)).DeltaPx;
3835
await Assert.That(playbackDelta).IsBetween(0, 6);
3936
}
4037
finally
@@ -345,29 +342,6 @@ await StepUntilWordAsync(
345342
}
346343
}
347344

348-
private static Task<double> MeasureOrpDeltaAsync(Microsoft.Playwright.IPage page) =>
349-
page.EvaluateAsync<double>(
350-
"""
351-
ids => {
352-
const line = document.querySelector(`[data-test="${ids.line}"]`);
353-
const orp = document.querySelector(`[data-test="${ids.orp}"]`);
354-
if (!line || !orp) {
355-
return 999;
356-
}
357-
358-
const lineRect = line.getBoundingClientRect();
359-
const orpRect = orp.getBoundingClientRect();
360-
const lineCenter = lineRect.left + (lineRect.width / 2);
361-
const orpCenter = orpRect.left + (orpRect.width / 2);
362-
return Math.abs(lineCenter - orpCenter);
363-
}
364-
""",
365-
new
366-
{
367-
line = UiTestIds.Learn.OrpLine,
368-
orp = UiTestIds.Learn.WordOrp
369-
});
370-
371345
private static Task<int> CountContextWordsAsync(Microsoft.Playwright.IPage page, string contextTestId) =>
372346
page.EvaluateAsync<int>(
373347
"""
@@ -411,8 +385,9 @@ private static async Task StepUntilWordAsync(Microsoft.Playwright.IPage page, st
411385
Assert.Fail("Unexpected execution path.");
412386
}
413387

414-
private static Task WaitForLearnLayoutReadyAsync(Microsoft.Playwright.IPage page) =>
415-
page.WaitForFunctionAsync(
388+
private static async Task<OrpDeltaMeasurement> WaitForLearnLayoutReadyAsync(Microsoft.Playwright.IPage page)
389+
{
390+
var handle = await page.WaitForFunctionAsync(
416391
"""
417392
args => {
418393
const display = document.querySelector(`[data-test="${args.displayTestId}"]`);
@@ -425,7 +400,9 @@ private static Task WaitForLearnLayoutReadyAsync(Microsoft.Playwright.IPage page
425400
const lineRect = line.getBoundingClientRect();
426401
const orpRect = orp.getBoundingClientRect();
427402
const delta = Math.abs((lineRect.left + (lineRect.width / 2)) - (orpRect.left + (orpRect.width / 2)));
428-
return delta <= args.maxOrpDeltaPx;
403+
return delta <= args.maxOrpDeltaPx
404+
? { DeltaPx: delta }
405+
: false;
429406
}
430407
""",
431408
new
@@ -438,6 +415,9 @@ private static Task WaitForLearnLayoutReadyAsync(Microsoft.Playwright.IPage page
438415
orpTestId = UiTestIds.Learn.WordOrp
439416
});
440417

418+
return await handle.JsonValueAsync<OrpDeltaMeasurement>();
419+
}
420+
441421
private static async Task ExpectFocusWordAsync(Microsoft.Playwright.IPage page, string expectedWord)
442422
{
443423
await Expect(page.GetByTestId(UiTestIds.Learn.Word))

tests/PrompterOne.Web.UITests.Reader/Reader/ReaderPlaybackTimingTests.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ await Expect(playToggle)
5252
await Assert.That(samples.Select(sample => sample.EffectiveWpm).ToArray()).IsEquivalentTo(TeleprompterEffectiveWpmSequence, CollectionOrdering.Matching);
5353

5454
var timingTolerance = BrowserTestConstants.ReaderTiming.TeleprompterTimingToleranceMs
55-
+ BrowserTestConstants.ReaderTiming.CapturePollIntervalMs * 2;
55+
+ BrowserTestConstants.ReaderTiming.CapturePollIntervalMs
56+
* BrowserTestConstants.ReaderTiming.CapturePollTimingSlackMultiplier;
5657

5758
for (var sampleIndex = 1; sampleIndex < samples.Length; sampleIndex++)
5859
{
@@ -377,7 +378,8 @@ private static async Task AssertLearnTimingMatches(
377378
: Math.Max(
378379
BrowserTestConstants.ReaderTiming.LearnTimingToleranceMs,
379380
(int)Math.Ceiling(expectedDelay * BrowserTestConstants.ReaderTiming.LearnTimingToleranceRatio))
380-
+ BrowserTestConstants.ReaderTiming.CapturePollIntervalMs * 2;
381+
+ BrowserTestConstants.ReaderTiming.CapturePollIntervalMs
382+
* BrowserTestConstants.ReaderTiming.CapturePollTimingSlackMultiplier;
381383

382384
await Assert.That(previousSample.Word).IsEqualTo(expected.Word);
383385
if (sampleIndex == 1)

tests/PrompterOne.Web.UITests.Studio/GoLive/GoLiveShellSessionFlowTests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,19 @@ await page.WaitForFunctionAsync(
328328
BrowserTestConstants.GoLive.RuntimeSessionId,
329329
new() { Timeout = BrowserTestConstants.Timing.ExtendedVisibleTimeoutMs });
330330

331+
var activeRuntimeState = await page.EvaluateAsync<JsonElement>(
332+
BrowserTestConstants.GoLive.GetRuntimeStateScript,
333+
BrowserTestConstants.GoLive.RuntimeSessionId);
334+
var activeRecordingSizeBytes = activeRuntimeState
335+
.GetProperty("recording")
336+
.GetProperty("sizeBytes")
337+
.GetInt64();
338+
339+
await page.WaitForFunctionAsync(
340+
BrowserTestConstants.GoLive.RecordingRuntimePayloadGrowthScript,
341+
new object[] { BrowserTestConstants.GoLive.RuntimeSessionId, activeRecordingSizeBytes },
342+
new() { Timeout = BrowserTestConstants.Timing.ExtendedVisibleTimeoutMs });
343+
331344
await UiInteractionDriver.ClickAndContinueAsync(
332345
page.GetByTestId(UiTestIds.GoLive.StartRecording),
333346
noWaitAfter: true);

tests/PrompterOne.Web.UITests/Support/BrowserTestConstants.ScreenFlows.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ public static class TeleprompterFlow
442442
public static class ReaderTiming
443443
{
444444
public const int CapturePollIntervalMs = 20;
445+
public const int CapturePollTimingSlackMultiplier = 3;
445446
public const int BoundaryTransitionSampleIndex = 4;
446447
public const int LearnTimingToleranceMs = 200;
447448
public const int LearnStartupTimingToleranceMs = 1800;

0 commit comments

Comments
 (0)