Skip to content

Commit ca6bb2b

Browse files
authored
Improve SEO metadata and rewrite README (#41)
* Improve SEO metadata and rewrite README for toolkit rebrand SEO fixes: - Add sitemap.ts and robots.ts for search engine indexing - Add JSON-LD structured data (SoftwareApplication schema) - Add viewport export with theme-color for light/dark modes - Add canonical URLs to all pages - Fix homepage title (9 chars → 50 chars) and description (169 → 120 chars) - Add title.template ("%s | Relaycode") for consistent sub-page titles - Update keywords to include Studio, Solidity, PolkaVM, Dedot - Fix siteName in openGraph (was using page title instead of "Relaycode") README: - Rewrite to reflect toolkit rebrand (not just extrinsic builder) - Add OG banner images for each tool section - Document Contract Studio, Extrinsic Builder, Component Docs - Update tech stack table, getting started, and project structure * Update utils tests for title template and robots changes
1 parent 1ea1e53 commit ca6bb2b

14 files changed

Lines changed: 281 additions & 92 deletions

File tree

README.md

Lines changed: 149 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,165 @@
1-
# Relaycode: Rethinking Extrinsics in Polkadot
1+
# Relaycode
22

33
[![CI](https://github.com/itsyogesh/relaycode/actions/workflows/ci.yml/badge.svg)](https://github.com/itsyogesh/relaycode/actions/workflows/ci.yml)
44
[![codecov](https://codecov.io/gh/itsyogesh/relaycode/branch/master/graph/badge.svg)](https://codecov.io/gh/itsyogesh/relaycode)
55
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
66
[![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](https://www.typescriptlang.org/)
77
[![W3F Grant](https://img.shields.io/badge/Web3_Foundation-Grant-green.svg)](https://grants.web3.foundation/)
88

9-
## Project Overview
10-
Relaycode is an intuitive extrinsics builder designed to transform the way developers and users interact with extrinsics in the Polkadot ecosystem. By bridging the gap between complex pallet operations and user-friendly interfaces, Relaycode gives both regular users and developers the ability to harness the full potential of extrinsics the Polkadot ecosystem.
9+
The developer toolkit for Polkadot. Build extrinsics, write smart contracts, and interact with Substrate chains — all from your browser.
1110

12-
### Key Features:
11+
<p align="center">
12+
<img src="public/og/home.png" alt="Relaycode — The Developer Toolkit for Polkadot" width="800"/>
13+
</p>
1314

14-
1. **A New Extrinsic Builder**: Our state-of-the-art builder allows users to construct extrinsics with ease, providing real-time encoding and decoding for immediate visual feedback.
15+
## Tools
1516

16-
2. **Dual-Pane Interface**: Relaycode lets you see the best of both worlds with our split-view design. Build extrinsics using human-readable inputs on one side, while simultaneously viewing the corresponding encoded data on the other.
17+
### Contract Studio
1718

18-
3. **Bi-Directional Editing**: Seamlessly switch between editing human-readable values and raw encoded data. Changes in one pane are instantly reflected in the other, offering unparalleled flexibility.
19+
<img src="public/og/studio.png" alt="Relaycode Studio" width="600"/>
1920

20-
4. **Wallet Integration**: Connect your Polkadot wallet directly within Relaycode to sign and submit extrinsics, eliminating the need for external tools or interfaces.
21+
Browser-based smart contract IDE for Polkadot Hub. Write Solidity, compile to EVM or PVM (PolkaVM), and deploy with native Polkadot wallets. No CLI, no MetaMask, no fragmented toolchain.
2122

22-
5. **Customizable Snippets**: Create, save, and share reusable extrinsic templates. Streamline complex processes by chaining multiple calls into a single, user-friendly form.
23+
**[relaycode.org/studio](https://relaycode.org/studio)**
2324

24-
6. **Educational Tools**: Built-in guides and tooltips help users understand the intricacies of extrinsics, making Relaycode an excellent learning platform for Polkadot users.
25+
### Extrinsic Builder
2526

26-
<p align="center">
27-
<img src="docs/demo.gif" alt="Relaycode Demo" width="800"/>
28-
</p>
27+
<img src="public/og/builder.png" alt="Relaycode Builder" width="600"/>
28+
29+
Visual extrinsic builder for the Polkadot ecosystem. Build, encode, decode, and submit any Substrate extrinsic with a dual-pane interface. Supports all pallets across all chains.
30+
31+
**[relaycode.org/builder](https://relaycode.org/builder)**
32+
33+
### Component Docs
34+
35+
Documentation for input components, encoding/decoding APIs, and usage guides. Built with Fumadocs.
36+
37+
**[relaycode.org/docs](https://relaycode.org/docs)**
38+
39+
### Substrate Utilities *(planned)*
40+
41+
SS58, EVM, and hex address converter plus other Substrate utilities.
42+
43+
## Tech Stack
44+
45+
| Layer | Technology |
46+
|-------|-----------|
47+
| **Framework** | Next.js 15 (App Router) |
48+
| **Language** | TypeScript (strict mode) |
49+
| **Styling** | Tailwind CSS + shadcn/ui |
50+
| **Polkadot Client** | [Dedot](https://github.com/dedotdev/dedot) |
51+
| **Wallet** | [LunoKit](https://github.com/nickytonline/luno-kit) (Polkadot.js, Talisman, SubWallet) |
52+
| **Smart Contracts** | Solidity → EVM / PVM via PolkaVM |
53+
| **Docs** | [Fumadocs](https://fumadocs.vercel.app/) |
54+
| **Testing** | Jest + React Testing Library |
55+
| **Deployment** | Vercel (Edge + Serverless) |
56+
| **Package Manager** | Yarn 1.x |
57+
58+
### Supported Chains
59+
60+
Polkadot, Kusama, Westend, Paseo, Asset Hubs, People chains, Coretime chains.
61+
62+
## Getting Started
63+
64+
### Prerequisites
65+
66+
- Node.js 18+
67+
- Yarn 1.x (`npm install -g yarn`)
68+
69+
### Setup
70+
71+
```bash
72+
# Clone the repository
73+
git clone https://github.com/itsyogesh/relaycode.git
74+
cd relaycode
75+
76+
# Install dependencies
77+
yarn install
78+
79+
# Start the development server
80+
yarn dev
81+
```
82+
83+
Open [http://localhost:3000](http://localhost:3000) in your browser.
84+
85+
### Environment Variables
86+
87+
Copy the example and configure:
88+
89+
```bash
90+
cp .env.example .env
91+
```
92+
93+
| Variable | Description | Default |
94+
|----------|------------|---------|
95+
| `NEXT_PUBLIC_APP_URL` | Application URL | `http://localhost:3000` |
96+
| `NEXT_PUBLIC_DEFAULT_CHAIN` | Default chain identifier | `pop-network-testnet` |
97+
| `NEXT_PUBLIC_SUPPORTED_CHAINS` | JSON array of supported chains | See `.env` |
98+
99+
### Available Commands
100+
101+
| Command | Description |
102+
|---------|------------|
103+
| `yarn dev` | Start development server |
104+
| `yarn build` | Production build |
105+
| `yarn start` | Start production server |
106+
| `yarn lint` | Run ESLint |
107+
| `yarn test` | Run Jest tests |
108+
| `yarn test:watch` | Run tests in watch mode |
109+
110+
## Project Structure
111+
112+
```
113+
app/
114+
(marketing)/ # Landing pages
115+
builder/ # Extrinsic builder
116+
studio/ # Contract Studio IDE
117+
docs/ # Documentation (Fumadocs)
118+
api/
119+
og/ # Dynamic OG image generation
120+
compile/ # Solidity compilation endpoint
121+
components/
122+
builder/ # Extrinsic builder components
123+
studio/ # Contract Studio components
124+
params/inputs/ # Substrate type input components
125+
ui/ # shadcn/ui base components
126+
context/ # React context providers
127+
hooks/ # Custom React hooks
128+
lib/ # Utility libraries
129+
types/ # TypeScript type definitions
130+
```
131+
132+
### Input Components
133+
134+
The extrinsic builder includes type-aware input components for every Substrate type:
135+
136+
Account, Amount, Balance, Bool, BTreeMap, BTreeSet, Bytes, Call, Enum, Hash (H160/H256/H512), KeyValue, Moment, Option, Struct, Text, Tuple, Vector, VectorFixed, Vote, VoteThreshold.
137+
138+
Each component maps directly to SCALE-encoded Substrate types and supports validation, encoding, and real-time feedback.
139+
140+
## Deployment
141+
142+
Relaycode is deployed on Vercel. Pushes to `master` trigger automatic production deployments.
143+
144+
OG images are generated dynamically at the edge via `next/og` ImageResponse routes:
145+
146+
- `/api/og/home` — Homepage
147+
- `/api/og/studio` — Contract Studio
148+
- `/api/og/builder` — Extrinsic Builder
149+
- `/api/og/docs` — Documentation
150+
151+
## Contributing
152+
153+
1. Fork the repository
154+
2. Create a feature branch (`git checkout -b feat/my-feature`)
155+
3. Commit your changes
156+
4. Push to the branch (`git push origin feat/my-feature`)
157+
5. Open a Pull Request
158+
159+
## License
160+
161+
[Apache 2.0](LICENSE)
162+
163+
## Acknowledgments
29164

30-
## Technical Architecture
31-
- Frontend: Next.js 15 with App Router, React, TypeScript
32-
- Styling: Tailwind CSS, shadcn/ui components
33-
- State Management: React Hooks, Context API
34-
- Polkadot Integration: [Dedot](https://github.com/dedotdev/dedot)
35-
- Wallet: [LunoKit](https://github.com/nickytonline/luno-kit) (Polkadot.js, Talisman, SubWallet)
36-
- Chains: Polkadot, Kusama, Westend (testnet)
37-
- Theming: next-themes for dark/light mode support
38-
39-
## Documentation
40-
41-
- [API Reference](docs/api/README.md) - Core encoding, decoding, and validation APIs
42-
- [Component Reference](docs/components/README.md) - Input component documentation
43-
- [Getting Started Tutorial](docs/tutorial/getting-started.md) - Build your first extrinsic
44-
- [Advanced Usage](docs/tutorial/advanced.md) - Bi-directional editing, batch calls, complex types
45-
- [Testing Guide](docs/testing-guide.md) - How to run and write tests
46-
47-
## Milestones
48-
49-
For detailed project milestones and deliverables, see our [Milestones](docs/relaycode.md) documentation.
50-
51-
### Implemented Input Components
52-
53-
The following input components have been implemented for the extrinsic builder:
54-
55-
- [x] **Account** - Handles `AccountId`, `Address`, `LookupSource`, `MultiAddress`
56-
- [x] **Amount** - Handles `i8`, `i16`, `i32`, `i64`, `i128`, `u8`, `u16`, `u32`, `u64`, `u128`, `Compact<uN>`
57-
- [x] **Balance** - Handles `Balance`, `BalanceOf`, `Compact<Balance>`, `Compact<BalanceOf>`
58-
- [x] **Bool** - Handles `bool`
59-
- [x] **BTreeMap** - Handles `BTreeMap<K, V>` with typed key-value pair inputs
60-
- [x] **BTreeSet** - Handles `BTreeSet<T>` with duplicate detection
61-
- [x] **Bytes** - Handles `Bytes`, `Vec<u8>`
62-
- [x] **Call** - Handles `Call`, `RuntimeCall`
63-
- [x] **Enum** - Handles enum types from metadata
64-
- [x] **Hash160** - Handles `H160` (20-byte hash)
65-
- [x] **Hash256** - Handles `Hash`, `H256` (32-byte hash)
66-
- [x] **Hash512** - Handles `H512` (64-byte hash)
67-
- [x] **KeyValue** - Handles `KeyValue`
68-
- [x] **Moment** - Handles `Moment`, `MomentOf`
69-
- [x] **Option** - Handles `Option<T>`
70-
- [x] **Text** - Handles `String`, `Text` (and fallback for unknown types)
71-
- [x] **Struct** - Handles composite/struct types
72-
- [x] **Tuple** - Handles tuple types `(T1, T2, ...)`
73-
- [x] **Vector** - Handles `Vec<T>`, `BoundedVec<T, S>`
74-
- [x] **VectorFixed** - Handles fixed-length arrays `[T; N]`
75-
- [x] **Vote** - Handles `Vote`
76-
- [x] **VoteThreshold** - Handles `VoteThreshold`
77-
78-
### M2 Features
79-
80-
- [x] **Chain Selector** - Switch between Polkadot, Kusama, and Westend (testnet) from the navbar
81-
- [x] **Type Badges** - Builder displays Substrate type names alongside field labels
82-
- [x] **Wallet Integration** - LunoKit-based wallet connect (Polkadot.js, Talisman, SubWallet)
83-
- [x] **Bi-Directional Editing** - Edit via form or raw hex, with real-time sync
84-
- [x] **Transaction Submission** - Sign and submit extrinsics directly from the builder
85-
- [x] **Input Validation** - Pre-submission validation with descriptive error messages
165+
Funded by a [Web3 Foundation](https://web3.foundation/) grant. Built with [Dedot](https://github.com/dedotdev/dedot) and [LunoKit](https://github.com/nickytonline/luno-kit).

__tests__/lib/utils.test.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,19 @@ describe("absoluteUrl", () => {
5858
describe("constructMetadata", () => {
5959
it("returns defaults when called with no args", () => {
6060
const meta = constructMetadata();
61-
expect(meta.title).toBe("Relaycode");
62-
expect(meta.description).toBe("Test description");
61+
expect(meta.title).toEqual({
62+
default: expect.any(String),
63+
template: "%s | Relaycode",
64+
});
65+
expect(meta.description).toBeDefined();
6366
});
6467

6568
it("uses custom values", () => {
6669
const meta = constructMetadata({
6770
title: "Custom Title",
6871
description: "Custom description",
6972
});
70-
expect(meta.title).toBe("Custom Title");
73+
expect((meta.title as any).default).toBe("Custom Title");
7174
expect(meta.description).toBe("Custom description");
7275
});
7376

@@ -78,6 +81,6 @@ describe("constructMetadata", () => {
7881

7982
it("does not include robots when noIndex is false", () => {
8083
const meta = constructMetadata({ noIndex: false });
81-
expect(meta.robots).toBeUndefined();
84+
expect(meta.robots).toEqual({ index: true, follow: true });
8285
});
8386
});

app/builder/layout.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ import { SiteFooter } from "@/components/layout/site-footer";
44
import { Blocks } from "lucide-react";
55

66
export const metadata: Metadata = {
7-
title: "Relaycode Builder — Polkadot Extrinsic Builder",
7+
title: "Extrinsic Builder — Build and Submit Substrate Extrinsics",
88
description:
9-
"Build, encode, decode, and submit any Substrate extrinsic visually. Supports all pallets across the Polkadot ecosystem.",
9+
"Visual extrinsic builder for Polkadot. Build, encode, decode, and submit any pallet call across all Substrate chains.",
1010
openGraph: {
1111
images: [{ url: "/api/og/builder", width: 1200, height: 630 }],
1212
},
1313
twitter: {
1414
card: "summary_large_image",
1515
images: ["/api/og/builder"],
1616
},
17+
alternates: {
18+
canonical: "/builder",
19+
},
1720
};
1821

1922
interface BuilderLayoutProps {

app/docs/layout.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ import { DocsLayout } from "fumadocs-ui/layouts/docs";
44
import { source } from "@/lib/source";
55

66
export const metadata: Metadata = {
7-
title: "Relaycode Docs — Developer Documentation",
7+
title: "Docs — Guides, References, and Examples",
88
description:
9-
"Developer documentation for the Relaycode toolkit. Guides, references, and examples for building on Polkadot.",
9+
"Developer documentation for Relaycode. Guides, API references, and examples for building on Polkadot with Substrate.",
1010
openGraph: {
1111
images: [{ url: "/api/og/docs", width: 1200, height: 630 }],
1212
},
1313
twitter: {
1414
card: "summary_large_image",
1515
images: ["/api/og/docs"],
1616
},
17+
alternates: {
18+
canonical: "/docs",
19+
},
1720
};
1821

1922
export default function Layout({ children }: { children: ReactNode }) {

app/layout.tsx

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import "@/styles/globals.css";
22

3+
import type { Viewport } from "next";
34
import { Nunito } from "next/font/google";
45
import { GeistMono } from "geist/font/mono";
56
import { GeistSans } from "geist/font/sans";
@@ -23,12 +24,53 @@ const nunito = Nunito({
2324
variable: "--font-nunito",
2425
});
2526

27+
export const viewport: Viewport = {
28+
width: "device-width",
29+
initialScale: 1,
30+
maximumScale: 5,
31+
themeColor: [
32+
{ media: "(prefers-color-scheme: light)", color: "#ffffff" },
33+
{ media: "(prefers-color-scheme: dark)", color: "#0a0a0a" },
34+
],
35+
};
36+
2637
export const metadata = constructMetadata();
2738

2839
export default function RootLayout({ children }: RootLayoutProps) {
2940
return (
3041
<html lang="en" suppressHydrationWarning>
31-
<head />
42+
<head>
43+
<script
44+
type="application/ld+json"
45+
dangerouslySetInnerHTML={{
46+
__html: JSON.stringify({
47+
"@context": "https://schema.org",
48+
"@type": "SoftwareApplication",
49+
name: "Relaycode",
50+
url: "https://relaycode.org",
51+
applicationCategory: "DeveloperApplication",
52+
operatingSystem: "Web",
53+
description:
54+
"Build extrinsics, write smart contracts, and interact with Substrate chains. Browser-based tools for the Polkadot ecosystem.",
55+
offers: {
56+
"@type": "Offer",
57+
price: "0",
58+
priceCurrency: "USD",
59+
},
60+
author: {
61+
"@type": "Person",
62+
name: "itsyogesh",
63+
url: "https://github.com/itsyogesh",
64+
},
65+
funder: {
66+
"@type": "Organization",
67+
name: "Web3 Foundation",
68+
url: "https://web3.foundation",
69+
},
70+
}),
71+
}}
72+
/>
73+
</head>
3274
<body
3375
className={cn(
3476
"min-h-screen bg-background font-sans antialiased",

app/robots.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { MetadataRoute } from "next";
2+
3+
export default function robots(): MetadataRoute.Robots {
4+
return {
5+
rules: [
6+
{
7+
userAgent: "*",
8+
allow: "/",
9+
disallow: ["/api/", "/_next/"],
10+
},
11+
],
12+
sitemap: "https://relaycode.org/sitemap.xml",
13+
host: "https://relaycode.org",
14+
};
15+
}

0 commit comments

Comments
 (0)