Skip to content

Commit 9a5c194

Browse files
committed
gh page
1 parent 4440f97 commit 9a5c194

31 files changed

+1278
-92
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: Deploy GitHub Pages
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
release:
8+
types:
9+
- published
10+
workflow_dispatch:
11+
12+
permissions:
13+
contents: read
14+
pages: write
15+
id-token: write
16+
17+
concurrency:
18+
group: github-pages
19+
cancel-in-progress: true
20+
21+
env:
22+
APP_PROJECT: src/PrompterLive.App/PrompterLive.App.csproj
23+
PAGES_ARTIFACT_ROOT: ${{ runner.temp }}/prompterlive-pages
24+
PAGES_BASE_PATH: /${{ github.event.repository.name }}/
25+
PUBLISH_ROOT: ${{ runner.temp }}/prompterlive-publish
26+
27+
jobs:
28+
deploy:
29+
runs-on: ubuntu-latest
30+
environment:
31+
name: github-pages
32+
url: ${{ steps.deployment.outputs.page_url }}
33+
34+
steps:
35+
- name: Checkout
36+
uses: actions/checkout@v4
37+
38+
- name: Setup .NET
39+
uses: actions/setup-dotnet@v4
40+
with:
41+
global-json-file: global.json
42+
43+
- name: Configure GitHub Pages
44+
uses: actions/configure-pages@v5
45+
46+
- name: Publish standalone WASM app
47+
run: >
48+
dotnet publish
49+
"$APP_PROJECT"
50+
-c Release
51+
-o "$PUBLISH_ROOT"
52+
-p:PrompterLiveBuildNumber=${{ github.run_number }}
53+
54+
- name: Prepare GitHub Pages artifact
55+
run: |
56+
mkdir -p "$PAGES_ARTIFACT_ROOT"
57+
cp -R "$PUBLISH_ROOT/wwwroot/." "$PAGES_ARTIFACT_ROOT/"
58+
sed -i "s#<base href=\"/\" />#<base href=\"${PAGES_BASE_PATH}\" />#g" "$PAGES_ARTIFACT_ROOT/index.html"
59+
cp "$PAGES_ARTIFACT_ROOT/index.html" "$PAGES_ARTIFACT_ROOT/404.html"
60+
touch "$PAGES_ARTIFACT_ROOT/.nojekyll"
61+
62+
- name: Upload Pages artifact
63+
uses: actions/upload-pages-artifact@v3
64+
with:
65+
path: ${{ env.PAGES_ARTIFACT_ROOT }}
66+
67+
- name: Deploy to GitHub Pages
68+
id: deployment
69+
uses: actions/deploy-pages@v4

AGENTS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ Repo-specific design rules:
299299
- Repo-owned manifests, scripts, workflows, and project files that track third-party runtime JavaScript SDKs MUST point to concrete GitHub release versions and asset URLs, never floating references.
300300
- Any vendored runtime JavaScript SDK that tracks an upstream GitHub repo MUST have an automated watcher job that checks new GitHub releases and opens a repo issue describing the required update when a newer release appears.
301301
- Build quality gates must stay green under `-warnaserror`.
302+
- GitHub Pages is the expected CI publish target for the standalone WebAssembly app; publish automation must keep the app browser-only and Pages-compatible.
303+
- Version text shown in the app must come from automated build or release metadata, never from manually edited About copy.
302304
- The runtime must negotiate browser language from supported cultures and default to English.
303305
- Supported runtime cultures are English, Ukrainian, French, Spanish, Portuguese, and Italian.
304306
- Russian must never be added as a supported runtime culture.
@@ -342,6 +344,7 @@ Ask first:
342344
- backend creep in the standalone runtime
343345
- random-port local startup
344346
- brittle selectors without `data-testid`
347+
- mixed-language root README or public entry docs; keep them English-only unless the user explicitly asks otherwise
345348
- design drift from `new-design`
346349
- any visible typing latency in the editor; plain input must feel immediate with no observable delay
347350
- editor keystroke paths that persist, compile, or rebuild shared session state; keep plain typing in memory and move heavier local sync to debounce or autosave

Directory.Build.props

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
<Project>
22
<PropertyGroup>
33
<PrompterLiveTargetFramework>net10.0</PrompterLiveTargetFramework>
4-
<PrompterLiveVersionPrefix>0.1.0</PrompterLiveVersionPrefix>
4+
<PrompterLiveVersionMajorMinor>0.1</PrompterLiveVersionMajorMinor>
5+
<PrompterLiveBuildNumber Condition="'$(PrompterLiveBuildNumber)' == '' and '$(GITHUB_RUN_NUMBER)' != ''">$(GITHUB_RUN_NUMBER)</PrompterLiveBuildNumber>
6+
<PrompterLiveBuildNumber Condition="'$(PrompterLiveBuildNumber)' == ''">0</PrompterLiveBuildNumber>
7+
<PrompterLiveVersionPrefix>$(PrompterLiveVersionMajorMinor).$(PrompterLiveBuildNumber)</PrompterLiveVersionPrefix>
58
<PrompterLiveAssemblyVersion>0.1.0.0</PrompterLiveAssemblyVersion>
6-
<PrompterLiveFileVersion>0.1.0.0</PrompterLiveFileVersion>
9+
<PrompterLiveFileVersion>$(PrompterLiveVersionPrefix).0</PrompterLiveFileVersion>
710

811
<TargetFramework Condition="'$(TargetFramework)' == ''">$(PrompterLiveTargetFramework)</TargetFramework>
912
<Nullable>enable</Nullable>

README.md

Lines changed: 209 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,209 @@
1-
# Teleprompter
1+
# PrompterLive
2+
3+
`PrompterLive` is a browser-first teleprompter and rehearsal tool for authors, speakers, streamers, editors, and production teams.
4+
5+
It is not a server product and not a desktop wrapper. The current runtime shape is a **standalone Blazor WebAssembly app** that boots directly in the browser, stores working state on the client, uses browser camera and microphone APIs, and can publish its WebAssembly build to GitHub Pages.
6+
7+
## Production URL
8+
9+
- GitHub Pages target: [https://managedcode.github.io/PrompterLive/](https://managedcode.github.io/PrompterLive/)
10+
- Publish workflow: [`.github/workflows/deploy-github-pages.yml`](.github/workflows/deploy-github-pages.yml)
11+
12+
`PrompterLive` is published as a repository Pages site. After the publish workflow runs, the WebAssembly artifact is served as a static site with no separate backend.
13+
14+
## What It Is
15+
16+
`PrompterLive` combines several workflows into a single product:
17+
18+
- `Library` for script and folder management
19+
- `Editor` for TPS authoring and speech-structure editing
20+
- `Learn` for RSVP rehearsal mode
21+
- `Teleprompter` for the classic reading surface
22+
- `Go Live` for browser-side live output, preview, and routing
23+
- `Settings` for camera, microphone, theme, and runtime preferences
24+
25+
Architecture map: [docs/Architecture.md](docs/Architecture.md)
26+
27+
## Key Properties
28+
29+
- standalone Blazor WebAssembly runtime with no server backend
30+
- UI ported from [`new-design/`](new-design/) as the design source of truth
31+
- TPS-focused editor for prompt-ready scripts
32+
- RSVP/Learn mode with ORP-style word rendering
33+
- browser-side media scene, device setup, and live preview
34+
- Go Live runtime with LiveKit and VDO.Ninja outputs
35+
- browser-local document and settings storage
36+
- browser-realistic acceptance tests through Playwright
37+
38+
## RSVP Inspiration
39+
40+
`PrompterLive` does not visually copy `Squirt`, but the `Learn` mode is directly inspired by the RSVP logic and pacing approach behind Squirt-style readers.
41+
42+
In practice that means:
43+
44+
- ORP-style focus on a key letter inside each word
45+
- word timing that reacts to word length and punctuation
46+
- natural pauses after commas, periods, and stronger phrase boundaries
47+
- a custom UI and layout adapted to `PrompterLive`, not a raw Squirt clone
48+
49+
Canonical inspiration: [cameron/squirt](https://github.com/cameron/squirt)
50+
51+
## Technical Model
52+
53+
- host: [`src/PrompterLive.App`](src/PrompterLive.App)
54+
- routed UI, CSS, browser interop: [`src/PrompterLive.Shared`](src/PrompterLive.Shared)
55+
- reusable domain logic: [`src/PrompterLive.Core`](src/PrompterLive.Core)
56+
- automated tests: [`tests/`](tests/)
57+
- visual reference: [`new-design/`](new-design/)
58+
59+
Further reading:
60+
61+
- architecture: [docs/Architecture.md](docs/Architecture.md)
62+
- settings media feedback: [docs/Features/SettingsMediaFeedback.md](docs/Features/SettingsMediaFeedback.md)
63+
- go live runtime: [docs/Features/GoLiveRuntime.md](docs/Features/GoLiveRuntime.md)
64+
- vendored streaming SDK policy: [docs/Features/VendoredStreamingSdkReleases.md](docs/Features/VendoredStreamingSdkReleases.md)
65+
- versioning and Pages publish: [docs/Features/AppVersioningAndGitHubPages.md](docs/Features/AppVersioningAndGitHubPages.md)
66+
67+
## App Version
68+
69+
The app version is shown in `Settings > About`.
70+
71+
Current scheme:
72+
73+
- local builds: `0.1.0`
74+
- CI builds: `0.1.<github.run_number>`
75+
76+
Version source of truth:
77+
78+
- [`Directory.Build.props`](Directory.Build.props)
79+
- [`src/PrompterLive.App/Program.cs`](src/PrompterLive.App/Program.cs)
80+
81+
Versioning and Pages workflow details: [docs/Features/AppVersioningAndGitHubPages.md](docs/Features/AppVersioningAndGitHubPages.md)
82+
83+
## Local Run
84+
85+
Requirements:
86+
87+
- [.NET 10 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/10.0)
88+
89+
Run:
90+
91+
```bash
92+
cd src/PrompterLive.App
93+
dotnet run
94+
```
95+
96+
Useful commands:
97+
98+
```bash
99+
dotnet build /Users/ksemenenko/Developer/PrompterLive/PrompterLive.slnx -warnaserror
100+
dotnet test /Users/ksemenenko/Developer/PrompterLive/PrompterLive.slnx
101+
dotnet format /Users/ksemenenko/Developer/PrompterLive/PrompterLive.slnx
102+
dotnet test /Users/ksemenenko/Developer/PrompterLive/PrompterLive.slnx --collect:"XPlat Code Coverage"
103+
```
104+
105+
## Deploy
106+
107+
Publish runs through the GitHub Actions workflow:
108+
109+
- [`.github/workflows/deploy-github-pages.yml`](.github/workflows/deploy-github-pages.yml)
110+
111+
What it does:
112+
113+
- builds `src/PrompterLive.App`
114+
- injects the CI build number into the app version
115+
- takes the published `wwwroot`
116+
- rewrites `base href` for the repository Pages path
117+
- adds `404.html` for client-side routing
118+
- deploys the artifact to GitHub Pages
119+
120+
Official platform reference: [GitHub Pages](https://docs.github.com/en/pages)
121+
122+
## Stack
123+
124+
- [.NET 10](https://dotnet.microsoft.com/en-us/download/dotnet/10.0)
125+
- [Blazor](https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor)
126+
- Razor Class Library
127+
- [xUnit](https://xunit.net/)
128+
- [bUnit](https://bunit.dev/)
129+
- [Playwright](https://playwright.dev/)
130+
131+
## Browser Media And Streaming Stack
132+
133+
`PrompterLive` is a browser-first media app, so it relies on standard Web APIs and a thin interop layer:
134+
135+
- [WebRTC API](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API)
136+
- [`getUserMedia()`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)
137+
- [MediaRecorder](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder)
138+
- [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)
139+
140+
Integrated streaming and media projects:
141+
142+
- [LiveKit](https://livekit.com/)
143+
docs: [Connecting to LiveKit](https://docs.livekit.io/intro/basics/connect/)
144+
repo: [livekit/client-sdk-js](https://github.com/livekit/client-sdk-js)
145+
- [VDO.Ninja](https://vdo.ninja/)
146+
repo: [steveseguin/vdo.ninja](https://github.com/steveseguin/vdo.ninja)
147+
148+
Pinned vendored SDK policy and version tracking:
149+
150+
- [docs/Features/VendoredStreamingSdkReleases.md](docs/Features/VendoredStreamingSdkReleases.md)
151+
152+
Currently pinned in the repository:
153+
154+
- `livekit/client-sdk-js` `v2.18.0`
155+
- `steveseguin/vdo.ninja` `v29.0`
156+
157+
## Fonts, Icons, And Visual Sources
158+
159+
- [Inter](https://rsms.me/inter/)
160+
- [JetBrains Mono](https://www.jetbrains.com/lp/mono/)
161+
- [Playfair Display](https://fonts.google.com/specimen/Playfair+Display)
162+
- [Google Fonts](https://fonts.google.com/)
163+
- [Feather Icons](https://feathericons.com/)
164+
165+
## Credits And Inspirations
166+
167+
These are the external projects, APIs, and references that `PrompterLive` builds on:
168+
169+
### Platform And Runtime
170+
171+
- [.NET 10](https://dotnet.microsoft.com/en-us/download/dotnet/10.0)
172+
- [Blazor](https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor)
173+
- [GitHub Pages](https://docs.github.com/en/pages)
174+
175+
### Test Infrastructure
176+
177+
- [xUnit](https://xunit.net/)
178+
- [bUnit](https://bunit.dev/)
179+
- [Playwright](https://playwright.dev/)
180+
181+
### Browser Media And Streaming
182+
183+
- [LiveKit](https://livekit.com/)
184+
- [LiveKit connection docs](https://docs.livekit.io/intro/basics/connect/)
185+
- [livekit/client-sdk-js](https://github.com/livekit/client-sdk-js)
186+
- [VDO.Ninja](https://vdo.ninja/)
187+
- [steveseguin/vdo.ninja](https://github.com/steveseguin/vdo.ninja)
188+
- [WebRTC API](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API)
189+
- [`getUserMedia()`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)
190+
- [MediaRecorder](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder)
191+
- [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)
192+
193+
### RSVP And Speed-Reading Inspiration
194+
195+
- [cameron/squirt](https://github.com/cameron/squirt)
196+
197+
### Typography And Icons
198+
199+
- [Inter](https://rsms.me/inter/)
200+
- [JetBrains Mono](https://www.jetbrains.com/lp/mono/)
201+
- [Playfair Display](https://fonts.google.com/specimen/Playfair+Display)
202+
- [Google Fonts](https://fonts.google.com/)
203+
- [Feather Icons](https://feathericons.com/)
204+
205+
If we missed someone in the credits, open an issue or PR and add the attribution explicitly instead of leaving the dependency implicit.
206+
207+
## License
208+
209+
This project is licensed under [MIT](LICENSE).

docs/Architecture.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ flowchart LR
109109
- `Directory.Packages.props` is the canonical source for NuGet package versions.
110110
- `Directory.Build.props` is the canonical source for shared target framework, analyzer policy, and assembly/app version settings.
111111
- `global.json` pins the expected .NET SDK for local and CI builds.
112+
- `.github/workflows/deploy-github-pages.yml` is the canonical GitHub Pages publish flow for the standalone WASM app, including CI run-number version injection and Pages artifact base-href rewriting.
112113
- Vendored browser SDK release pins live in `vendored-streaming-sdks.json`, and the exact release sync or watch flow is documented in `docs/Features/VendoredStreamingSdkReleases.md`.
113114

114115
## Runtime Boundaries
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# App Versioning And GitHub Pages
2+
3+
## Scope
4+
5+
`PrompterLive` exposes the running app version inside the Settings About screen and publishes the standalone WebAssembly build to GitHub Pages.
6+
7+
This flow keeps the version number automated:
8+
9+
- local builds default to `0.1.0`
10+
- CI builds derive `0.1.<run_number>` from the active GitHub Actions run
11+
- the About screen reads the compiled assembly metadata instead of hardcoded copy
12+
13+
## Version And Deploy Flow
14+
15+
```mermaid
16+
flowchart LR
17+
Run["GitHub Actions run_number<br/>or local default 0"]
18+
BuildProps["Directory.Build.props<br/>Version = 0.1.build"]
19+
Assembly["PrompterLive.App assembly metadata"]
20+
Program["Program.cs<br/>IAppVersionProvider"]
21+
About["Settings About card"]
22+
Publish["dotnet publish"]
23+
PagesPrep["deploy-github-pages.yml<br/>rewrite base href + copy 404.html"]
24+
Pages["GitHub Pages"]
25+
26+
Run --> BuildProps
27+
BuildProps --> Assembly
28+
Assembly --> Program
29+
Program --> About
30+
BuildProps --> Publish
31+
Publish --> PagesPrep
32+
PagesPrep --> Pages
33+
```
34+
35+
## Source Of Truth
36+
37+
- `Directory.Build.props` is the only source of app version composition.
38+
- `PrompterLiveBuildNumber` comes from `GITHUB_RUN_NUMBER` when CI provides it, or falls back to `0` locally.
39+
- `Program.cs` creates `IAppVersionProvider` from the compiled `PrompterLive.App` assembly metadata.
40+
- `SettingsAboutSection` renders that provider value in the About card subtitle.
41+
42+
## GitHub Pages Rules
43+
44+
- GitHub Pages publishes the standalone `src/PrompterLive.App` artifact only.
45+
- The workflow copies the published `wwwroot` output, not the host wrapper files around it.
46+
- The workflow rewrites `<base href="/">` to `/<repo-name>/` only inside the Pages artifact.
47+
- The workflow copies `index.html` to `404.html` so client-side routes keep working on repository Pages hosting.
48+
- `.nojekyll` must be present in the Pages artifact so framework and `_content` assets are served as-is.
49+
50+
## Verification
51+
52+
- `dotnet test /Users/ksemenenko/Developer/PrompterLive/tests/PrompterLive.App.Tests/PrompterLive.App.Tests.csproj --filter "FullyQualifiedName~SettingsInteractionTests.AboutSection_RendersInjectedAppVersionMetadata"`
53+
- `dotnet test /Users/ksemenenko/Developer/PrompterLive/tests/PrompterLive.App.UITests/PrompterLive.App.UITests.csproj --filter "FullyQualifiedName~TeleprompterSettingsFlowTests.TeleprompterAndSettingsScreens_RespondToCoreControls"`
54+
- `.github/workflows/deploy-github-pages.yml` publish step passes `-p:PrompterLiveBuildNumber=${{ github.run_number }}`

src/PrompterLive.App/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using PrompterLive.App;
55
using PrompterLive.App.Services;
66
using PrompterLive.Shared.Services;
7+
using PrompterLive.Shared.Settings.Services;
78

89
var builder = WebAssemblyHostBuilder.CreateDefault(args);
910

@@ -17,6 +18,7 @@
1718

1819
builder.Services.AddLocalization();
1920
builder.Services.AddSingleton<IFormFactor, FormFactor>();
21+
builder.Services.AddSingleton<IAppVersionProvider>(_ => AppVersionProviderFactory.CreateFromAssembly(typeof(Program).Assembly));
2022
builder.Services.AddPrompterLiveShared();
2123

2224
var host = builder.Build();

0 commit comments

Comments
 (0)