Skip to content
Closed
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
153 changes: 153 additions & 0 deletions .github/workflows/mobile-showcase-screenshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ jobs:
if: inputs.platform == 'all' || inputs.platform == 'ios'
runs-on: blacksmith-12vcpu-macos-26
timeout-minutes: 60
outputs:
artifact_id: ${{ steps.upload_ios.outputs.artifact-id }}
steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down Expand Up @@ -68,6 +70,7 @@ jobs:
run: pnpm screenshots:mobile --platform ios --appearance "${{ inputs.appearance }}" --validate-only

- name: Upload iOS screenshots
id: upload_ios
if: always()
uses: actions/upload-artifact@v7
with:
Expand All @@ -76,11 +79,160 @@ jobs:
if-no-files-found: warn
retention-days: 14

publish_marketing_preview:
name: Publish marketing mobile preview
if: |
always() &&
needs.ios.result == 'success' &&
needs.android.result == 'success' &&
inputs.platform == 'all' &&
github.ref == format('refs/heads/{0}', github.event.repository.default_branch) &&
inputs.appearance != 'light'
needs: [ios, android]
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 10
steps:
- id: app_token
name: Mint release app token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.RELEASE_APP_ID }}
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}

- name: Checkout default branch
uses: actions/checkout@v6
with:
ref: ${{ github.event.repository.default_branch }}
fetch-depth: 0
token: ${{ steps.app_token.outputs.token }}
persist-credentials: true

- name: Download iOS screenshots
uses: actions/download-artifact@v8
with:
name: app-store-connect-screenshots
path: ${{ runner.temp }}/mobile-showcase

- name: Download Android screenshots
uses: actions/download-artifact@v8
with:
name: google-play-screenshots
path: ${{ runner.temp }}/mobile-showcase

- id: app_bot
name: Resolve GitHub App bot identity
env:
GH_TOKEN: ${{ steps.app_token.outputs.token }}
APP_SLUG: ${{ steps.app_token.outputs.app-slug }}
run: |
user_id="$(gh api "/users/${APP_SLUG}[bot]" --jq .id)"
echo "name=${APP_SLUG}[bot]" >> "$GITHUB_OUTPUT"
echo "email=${user_id}+${APP_SLUG}[bot]@users.noreply.github.com" >> "$GITHUB_OUTPUT"

- id: preview
name: Update website preview asset
env:
IOS_ARTIFACT_ID: ${{ needs.ios.outputs.artifact_id }}
ANDROID_ARTIFACT_ID: ${{ needs.android.outputs.artifact_id }}
HEAD_SHA: ${{ github.sha }}
RUN_ID: ${{ github.run_id }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
WORKFLOW_NAME: ${{ github.workflow }}
run: |
output_directory="apps/marketing/public/mobile-states"
declare -A preview_sources=(
["threads.png"]="$RUNNER_TEMP/mobile-showcase/iphone-6.9/dark/threads.png"
["ipad-threads.png"]="$RUNNER_TEMP/mobile-showcase/ipad-13/dark/threads.png"
["ios-thread.png"]="$RUNNER_TEMP/mobile-showcase/iphone-6.9/dark/thread.png"
["ios-terminal.png"]="$RUNNER_TEMP/mobile-showcase/iphone-6.9/dark/terminal.png"
["ios-review.png"]="$RUNNER_TEMP/mobile-showcase/iphone-6.9/dark/review.png"
["ios-environments.png"]="$RUNNER_TEMP/mobile-showcase/iphone-6.9/dark/environments.png"
["android-threads.png"]="$RUNNER_TEMP/mobile-showcase/phone/dark/threads.png"
["android-thread.png"]="$RUNNER_TEMP/mobile-showcase/phone/dark/thread.png"
["android-terminal.png"]="$RUNNER_TEMP/mobile-showcase/phone/dark/terminal.png"
["android-review.png"]="$RUNNER_TEMP/mobile-showcase/phone/dark/review.png"
["android-environments.png"]="$RUNNER_TEMP/mobile-showcase/phone/dark/environments.png"
)

for output_name in "${!preview_sources[@]}"; do
source_path="${preview_sources[$output_name]}"
if [[ ! -f "$source_path" ]]; then
echo "Missing expected website preview source: $source_path" >&2
exit 1
fi
done

changed=false
for output_name in "${!preview_sources[@]}"; do
source_path="${preview_sources[$output_name]}"
output_path="$output_directory/$output_name"
if [[ ! -f "$output_path" ]] || ! cmp --silent "$source_path" "$output_path"; then
changed=true
break
fi
done

if [[ "$changed" == "false" ]]; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "Website previews already match the generated screenshots."
exit 0
fi

mkdir -p "$output_directory"
for output_name in "${!preview_sources[@]}"; do
cp "${preview_sources[$output_name]}" "$output_directory/$output_name"
done
node --input-type=module <<'NODE'
import { writeFile } from "node:fs/promises";

const metadata = {
artifacts: [
{
id: Number(process.env.IOS_ARTIFACT_ID),
name: "app-store-connect-screenshots",
},
{
id: Number(process.env.ANDROID_ARTIFACT_ID),
name: "google-play-screenshots",
},
],
artifactCreatedAt: new Date().toISOString(),
runId: Number(process.env.RUN_ID),
runUrl: process.env.RUN_URL,
headSha: process.env.HEAD_SHA,
workflow: process.env.WORKFLOW_NAME,
devices: ["iphone-6.9", "ipad-13", "pixel"],
scenes: ["thread", "terminal", "review", "threads", "environments"],
appearance: "dark",
};

await writeFile(
"apps/marketing/public/mobile-states/source.json",
`${JSON.stringify(metadata, null, 2)}\n`,
);
NODE
echo "changed=true" >> "$GITHUB_OUTPUT"

- name: Commit website preview
if: steps.preview.outputs.changed == 'true'
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: |
git config user.name "${{ steps.app_bot.outputs.name }}"
git config user.email "${{ steps.app_bot.outputs.email }}"
git add apps/marketing/public/mobile-states
git commit -m "chore(marketing): refresh mobile showcase screenshot"
git pull --rebase origin "$DEFAULT_BRANCH"
git push origin "HEAD:$DEFAULT_BRANCH"

android:
name: Android phone, 7-inch tablet, and 10-inch tablet
if: inputs.platform == 'all' || inputs.platform == 'android'
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 60
outputs:
artifact_id: ${{ steps.upload_android.outputs.artifact-id }}
env:
T3_SHOWCASE_ANDROID_ABI: x86_64
steps:
Expand Down Expand Up @@ -143,6 +295,7 @@ jobs:
run: pnpm screenshots:mobile --platform android --appearance "${{ inputs.appearance }}" --validate-only

- name: Upload Android screenshots
id: upload_android
if: always()
uses: actions/upload-artifact@v7
with:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ node_modules
*.log
*.tsbuildinfo
apps/*/dist
apps/marketing/public/sidebar-demo
infra/*/dist
.astro
packages/*/dist
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ This will launch T3 Code's backend on your machine as well as the local web app

Tip: Use `npx t3@latest --help` for the full CLI reference.

### Mobile apps

Control your T3 Code environments from your phone or tablet:

- [Download for iPhone and iPad on the App Store](https://apps.apple.com/us/app/t3-code-remote-claude-more/id6787819824)
- [Get the Android app on Google Play](https://play.google.com/store/apps/details?id=com.t3tools.t3code)

### Desktop app

Install the latest version of the desktop app from [GitHub Releases](https://github.com/pingdotgg/t3code/releases), or from your favorite package registry:
Expand Down
21 changes: 21 additions & 0 deletions apps/marketing/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
import { defineConfig } from "astro/config";

const cacheSidebarDemoAssets = {
name: "cache-sidebar-demo-assets",
configureServer(server) {
server.middlewares.use((request, response, next) => {
if (request.url?.startsWith("/sidebar-demo/assets/")) {
response.setHeader("Cache-Control", "public, max-age=31536000, immutable");
} else if (
request.url?.startsWith("/demo-states/") ||
request.url?.startsWith("/mobile-states/")
) {
response.setHeader("Cache-Control", "public, max-age=3600, stale-while-revalidate=86400");
}
next();
});
},
};

export default defineConfig({
site: "https://t3.codes",
server: {
port: Number(process.env.PORT ?? 4173),
},
vite: {
plugins: [cacheSidebarDemoAssets],
},
});
7 changes: 5 additions & 2 deletions apps/marketing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
"private": true,
"type": "module",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"dev": "npm run prepare:assets && astro dev",
"build": "npm run prepare:assets && astro build",
"prepare:assets": "npm run build:sidebar-demo",
"build:sidebar-demo": "npm run --prefix ../web build:sidebar-demo && node scripts/capture-demo-screenshots.mjs",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Demo build missing web deps

High Severity

Marketing build/dev now run build:sidebar-demo, which builds @t3tools/web into the gitignored public/sidebar-demo tree, but @t3tools/marketing does not depend on @t3tools/web. The Vercel install filter @t3tools/marketing... therefore never installs web’s packages, so the interactive hero demo cannot be produced in that environment and the marketing build fails.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 50e470c. Configure here.

"preview": "astro preview",
"typecheck": "astro check"
},
Expand All @@ -16,6 +18,7 @@
"devDependencies": {
"@astrojs/check": "^0.9.7",
"@vercel/config": "^0.3.0",
"playwright-core": "1.60.0",
"typescript": "catalog:"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 16 additions & 1 deletion apps/marketing/public/harnesses/opencode-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions apps/marketing/public/mobile-states/source.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"artifacts": [
{
"id": 8791333399,
"name": "app-store-connect-screenshots"
},
{
"id": 8791283952,
"name": "google-play-screenshots"
}
],
"artifactCreatedAt": "2026-07-31T10:54:46Z",
"runId": 30625175356,
"runUrl": "https://github.com/pingdotgg/t3code/actions/runs/30625175356",
"headSha": "0647dbc12be4e83b95337eb0bccbeaa982967d39",
"workflow": "mobile-showcase-screenshots.yml",
"devices": ["iphone-6.9", "ipad-13", "pixel"],
"scenes": ["thread", "terminal", "review", "threads", "environments"],
"appearance": "dark"
}
Binary file added apps/marketing/public/mobile-states/threads.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/marketing/public/nightly-clouds.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 50 additions & 0 deletions apps/marketing/public/nightly-stars.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/marketing/public/og-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/marketing/public/og-source.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/marketing/public/store-logos/appstore.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/marketing/public/store-logos/googleplay.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading