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
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:

- uses: Swatinem/rust-cache@v2
with:
workspaces: app/src-tauri
workspaces: apps/desktop/src-tauri

- name: install linux dependencies
if: matrix.os == 'ubuntu-22.04'
Expand All @@ -68,7 +68,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
projectPath: app
projectPath: apps/desktop
tagName: v__VERSION__
releaseName: 'Pontoon v__VERSION__'
releaseBody: 'Download the installer that matches your operating system.'
Expand Down
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ node_modules
# Build
build
dist
.next
*.tsbuildinfo

# Rust / Tauri
app/src-tauri/target/
app/src-tauri/gen/schemas/
app/src-tauri/binaries/
apps/desktop/src-tauri/target/
apps/desktop/src-tauri/gen/schemas/
apps/desktop/src-tauri/binaries/

# AI tools
.claude
Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ Highlights:

```
pontoon/ pnpm + TurboRepo monorepo
├── app/ @pontoon/app — Tauri + React 19 + Vite 6 + Tailwind 4 desktop GUI
│ ├── src/panels/ A1–A20 inspection panels
│ ├── src/rpc/ wire contract (57 methods), codec, message-tree types
│ └── src-tauri/ Tauri shell (spawns the bridge as a sidecar)
├── apps/
│ ├── desktop/ @pontoon/app — Tauri + React 19 + Vite 6 + Tailwind 4 desktop GUI
│ │ ├── src/panels/ A1–A20 inspection panels
│ │ ├── src/rpc/ wire contract (57 methods), codec, message-tree types
│ │ └── src-tauri/ Tauri shell (spawns the bridge as a sidecar)
│ └── website/ marketing + docs site
└── packages/
├── bridge/ @pontoon/bridge — real @ton/sandbox JSON-RPC bridge (default)
└── mock-bridge/ @pontoon/mock-bridge — canned fixtures for fast offline UI work
Expand All @@ -51,7 +53,7 @@ pontoon/ pnpm + TurboRepo monorepo
- `tree.ts` — `BlockchainTransaction[]` → message-tree (`TxNode`) + `vm_logs_full` → VM steps
- `encode.ts` — bigint↔decimal-string, Cell↔base64 BOC, address↔raw `0:<hex>`

**The frontend** never changes its wire contract — `app/src/rpc/contract.ts` is the fixed boundary both bridges satisfy. Most capabilities are fully real; four that need a user's Blueprint project + toolchain (`contract.deploy` by wrapper, `contract.abi` from `.abi.json`, `test.run`, FunC/Tact source coverage) degrade gracefully with a clear "attach a Blueprint project" note and light up once one is attached.
**The frontend** never changes its wire contract — `apps/desktop/src/rpc/contract.ts` is the fixed boundary both bridges satisfy. Most capabilities are fully real; four that need a user's Blueprint project + toolchain (`contract.deploy` by wrapper, `contract.abi` from `.abi.json`, `test.run`, FunC/Tact source coverage) degrade gracefully with a clear "attach a Blueprint project" note and light up once one is attached.

---

Expand All @@ -77,7 +79,7 @@ Then open the printed Vite URL. The UI auto-connects to the bridge at `127.0.0.1

```bash
pnpm desktop:dev # Tauri dev shell over the live Vite + bridge stack
pnpm desktop:build # production bundle (installers under app/src-tauri/target/release/bundle/)
pnpm desktop:build # production bundle (installers under apps/desktop/src-tauri/target/release/bundle/)
```

In dev the shell reuses the tsx bridge on `127.0.0.1:37631`. Production bundles embed the bridge as a compiled sidecar binary instead: the shell generates a session token, starts the sidecar on an OS-assigned local port, waits for its `READY <port>` signal after sandbox warmup, injects `window.__PONTOON_BRIDGE__`, and kills the sidecar on exit — so a packaged app and a dev stack can run side by side.
Expand Down Expand Up @@ -139,4 +141,4 @@ pnpm --filter @pontoon/bridge smoke

- `DESIGN.md` — UI design language and panel-by-panel reference.
- `PRODUCT.md` — product scope and the @ton/sandbox API → panel mapping.
- The wire contract (`app/src/rpc/`) is the contract between UI and bridge — keep both bridges in lockstep with it.
- The wire contract (`apps/desktop/src/rpc/`) is the contract between UI and bridge — keep both bridges in lockstep with it.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 11 additions & 10 deletions app/src-tauri/build.rs → apps/desktop/src-tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ fn main() {
}

fn build_sidecar() {
println!("cargo:rerun-if-changed=../../scripts/build-sidecar.mjs");
println!("cargo:rerun-if-changed=../../packages/bridge/package.json");
println!("cargo:rerun-if-changed=../../packages/bridge/tsconfig.json");
println!("cargo:rerun-if-changed=../../packages/bridge/server.ts");
println!("cargo:rerun-if-changed=../../packages/bridge/handlers.ts");
println!("cargo:rerun-if-changed=../../packages/bridge/state.ts");
println!("cargo:rerun-if-changed=../../packages/bridge/tree.ts");
println!("cargo:rerun-if-changed=../../packages/bridge/encode.ts");
println!("cargo:rerun-if-changed=../../pnpm-lock.yaml");
println!("cargo:rerun-if-changed=../../../scripts/build-sidecar.mjs");
println!("cargo:rerun-if-changed=../../../packages/bridge/package.json");
println!("cargo:rerun-if-changed=../../../packages/bridge/tsconfig.json");
println!("cargo:rerun-if-changed=../../../packages/bridge/server.ts");
println!("cargo:rerun-if-changed=../../../packages/bridge/handlers.ts");
println!("cargo:rerun-if-changed=../../../packages/bridge/state.ts");
println!("cargo:rerun-if-changed=../../../packages/bridge/tree.ts");
println!("cargo:rerun-if-changed=../../../packages/bridge/encode.ts");
println!("cargo:rerun-if-changed=../../../pnpm-lock.yaml");

let target = env::var("TARGET").expect("Cargo did not provide TARGET");
let manifest_dir = PathBuf::from(
Expand All @@ -23,7 +23,8 @@ fn build_sidecar() {
let repo_root = manifest_dir
.parent()
.and_then(|path| path.parent())
.expect("src-tauri should live two levels below the repository root");
.and_then(|path| path.parent())
.expect("src-tauri should live three levels below the repository root");
let script = repo_root.join("scripts").join("build-sidecar.mjs");

let status = Command::new("node")
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://schema.tauri.app/config/2",
"productName": "Pontoon",
"version": "0.1.0",
"identifier": "dev.entrypoint.pontoon",
"identifier": "xyz.entrypointlabs.pontoon",
"build": {
"beforeDevCommand": "pnpm -w dev",
"beforeBuildCommand": "pnpm build",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
155 changes: 155 additions & 0 deletions apps/website/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
@import "tailwindcss";

/* ─────────────────────────────────────────────────────────────────────────
Pontoon marketing site — dark-first, single theme. Tokens mirror the
product's design system (apps/desktop/src/styles.css): neutral charcoal
surfaces, one vibrant pontoon green reserved for signal. Marketing keeps
the same palette so the site and the app read as one product.
───────────────────────────────────────────────────────────────────────── */

:root {
--brand: oklch(0.78 0.155 163);
--brand-deep: oklch(0.62 0.135 163);
--brand-foreground: oklch(0.2 0.05 163);

--background: oklch(0.175 0.003 170);
--well: oklch(0.145 0.003 170);
--foreground: oklch(0.93 0.003 170);
--card: oklch(0.212 0.003 170);
--card-raised: oklch(0.235 0.004 170);
--muted: oklch(0.265 0.004 170);
--muted-foreground: oklch(0.66 0.006 170);
--faint-foreground: oklch(0.61 0.006 170);
--border: oklch(0.29 0.005 170);
--border-strong: oklch(0.37 0.006 170);
--rail: oklch(0.16 0.003 170);
--accent: oklch(0.285 0.008 168);

--success: oklch(0.74 0.14 158);
--warning: oklch(0.79 0.14 76);
--danger: oklch(0.64 0.19 25);

--radius: 0.625rem;
}

@theme inline {
--color-background: var(--background);
--color-well: var(--well);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-raised: var(--card-raised);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-faint: var(--faint-foreground);
--color-border: var(--border);
--color-border-strong: var(--border-strong);
--color-rail: var(--rail);
--color-accent: var(--accent);
--color-brand: var(--brand);
--color-brand-deep: var(--brand-deep);
--color-brand-foreground: var(--brand-foreground);
--color-success: var(--success);
--color-warning: var(--warning);
--color-danger: var(--danger);

--font-sans: var(--font-archivo), ui-sans-serif, system-ui, -apple-system, sans-serif;
--font-mono: var(--font-jetbrains), "SFMono-Regular", Consolas, ui-monospace, monospace;

--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 0.35rem);
}

* {
border-color: var(--border);
}

html {
scroll-behavior: smooth;
}

body {
background: var(--background);
color: var(--foreground);
font-family: var(--font-sans);
font-synthesis: none;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}

::selection {
background: color-mix(in oklch, var(--brand) 30%, transparent);
color: var(--foreground);
}

:focus-visible {
outline: 2px solid var(--brand);
outline-offset: 2px;
border-radius: 5px;
}

h1,
h2,
h3 {
text-wrap: balance;
}
p {
text-wrap: pretty;
}

.font-mono {
font-family: var(--font-mono);
font-feature-settings: "tnum" 1, "cv01" 1;
}

.tnum {
font-variant-numeric: tabular-nums;
}

/* Structural dot grid — the product's Local Sandbox backdrop. */
.dot-grid {
background-image: radial-gradient(circle at center, var(--border) 1px, transparent 1px);
background-size: 22px 22px;
}

/* Fine engineering grid for large section backdrops. */
.line-grid {
background-image:
linear-gradient(to right, var(--border) 1px, transparent 1px),
linear-gradient(to bottom, var(--border) 1px, transparent 1px);
background-size: 64px 64px;
}

/* Live-status dot — breathes only to signal connection, like the app. */
.live-dot {
position: relative;
}
.live-dot::after {
content: "";
position: absolute;
inset: -4px;
border-radius: 9999px;
background: var(--brand);
opacity: 0.35;
animation: live-pulse 2.4s ease-in-out infinite;
}

@keyframes live-pulse {
0%, 100% { transform: scale(0.7); opacity: 0.35; }
50% { transform: scale(1.15); opacity: 0; }
}

/* One orchestrated page-load reveal. */
.reveal {
opacity: 0;
transform: translateY(14px);
animation: reveal-in 0.7s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
@keyframes reveal-in {
to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.reveal { animation: none; opacity: 1; transform: none; }
.live-dot::after { animation: none; opacity: 0; }
}
39 changes: 39 additions & 0 deletions apps/website/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { Metadata } from "next";
import { Archivo, JetBrains_Mono } from "next/font/google";
import "./globals.css";

const archivo = Archivo({
subsets: ["latin"],
variable: "--font-archivo",
display: "swap"
});

const jetbrainsMono = JetBrains_Mono({
subsets: ["latin"],
variable: "--font-jetbrains",
display: "swap"
});

export const metadata: Metadata = {
metadataBase: new URL("https://pontoon.entrypointlabs.xyz"),
title: "Pontoon: the desktop inspector for @ton/sandbox",
description:
"Pontoon is a local-first desktop tool for @ton/sandbox. Deploy contracts, send messages, and watch the whole async transaction tree: phase-level fees, TVM traces, and state, without reading raw VM logs.",
keywords: ["TON", "@ton/sandbox", "Blueprint", "TVM", "smart contracts", "debugger", "desktop"],
openGraph: {
title: "Pontoon: the desktop inspector for @ton/sandbox",
description:
"Make TON's async execution visible. A local-first desktop debugger for @ton/sandbox.",
type: "website"
}
};

export default function RootLayout({
children
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en" className={`${archivo.variable} ${jetbrainsMono.variable}`}>
<body>{children}</body>
</html>
);
}
23 changes: 23 additions & 0 deletions apps/website/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { SiteNav } from "@/components/site-nav";
import { Hero } from "@/components/hero";
import { Features } from "@/components/features";
import { HowItWorks } from "@/components/how-it-works";
import { Panels } from "@/components/panels";
import { Cta } from "@/components/cta";
import { SiteFooter } from "@/components/site-footer";

export default function Home() {
return (
<>
<SiteNav />
<main>
<Hero />
<Features />
<HowItWorks />
<Panels />
<Cta />
</main>
<SiteFooter />
</>
);
}
46 changes: 46 additions & 0 deletions apps/website/components/cta.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { ArrowRight, Github } from "lucide-react";
import { PontoonMark } from "./pontoon-mark";
import { GITHUB_URL, RELEASES_URL } from "@/lib/site";

export function Cta() {
return (
<section className="border-b border-border">
<div className="mx-auto max-w-6xl px-6 py-24">
<div className="relative overflow-hidden rounded-2xl border border-border-strong bg-card px-8 py-16 text-center sm:px-16">
<div className="dot-grid pointer-events-none absolute inset-0 opacity-30 [mask-image:radial-gradient(ellipse_60%_80%_at_50%_50%,black,transparent)]" />
<div className="relative flex flex-col items-center">
<span className="grid h-12 w-12 place-items-center rounded-xl bg-rail ring-1 ring-border">
<PontoonMark size={28} />
</span>
<h2 className="mt-6 max-w-2xl text-3xl font-semibold tracking-[-0.02em] text-balance sm:text-4xl">
Debug your next TON transaction without reading a single VM log.
</h2>
<p className="mt-4 max-w-lg text-[15px] leading-relaxed text-muted-foreground">
Free and local-first. Open a project, send a message, and watch the tree.
</p>
<div className="mt-8 flex flex-wrap items-center justify-center gap-3">
<a
href={RELEASES_URL}
target="_blank"
rel="noreferrer"
className="group inline-flex items-center gap-2 rounded-lg bg-brand px-5 py-3 text-sm font-semibold text-brand-foreground transition-[filter] hover:brightness-105"
>
Download Pontoon
<ArrowRight size={16} className="transition-transform group-hover:translate-x-0.5" />
</a>
<a
href={GITHUB_URL}
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-2 rounded-lg border border-border bg-background/50 px-5 py-3 text-sm font-medium text-foreground transition-colors hover:border-border-strong"
>
<Github size={16} />
Star on GitHub
</a>
</div>
</div>
</div>
</div>
</section>
);
}
Loading