diff --git a/CHANGELOG.md b/CHANGELOG.md index d6ceb01..3a3a44c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ All notable changes to this project are documented in this file. - docs: split the README into `docs/` (getting started, configuration, HTTP API, architecture, development) - chore: drop Scrutinizer (`.scrutinizer.yml`, badges) — GitHub Actions is the only CI gate +- docs: publish a project page on GitHub Pages, with an animated LNURL-pay flow diagram + and an address-anatomy graphic **Full Changelog**: https://github.com/php-lightning/lnaddress/compare/0.9.0...main diff --git a/docs/index.html b/docs/index.html index d09305a..3d9e71d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -55,6 +55,7 @@ border-radius: 5px; padding: 1px 5px; font-size: 0.9em; + overflow-wrap: anywhere; } h1, h2, h3 { line-height: 1.25; letter-spacing: -0.015em; } h2 { margin-top: 3.2rem; font-size: 1.6rem; } @@ -122,6 +123,119 @@ @media (prefers-color-scheme: dark) { .steps li::before { color: #14161a; } } .steps h3 { margin: 0 0 4px; } + /* ---- figures: address anatomy + payment flow ---- */ + .fig { + margin: 1.8rem 0 0; + padding: 18px 16px 14px; + border: 1px solid var(--line); + border-radius: 12px; + background: var(--bg-soft); + } + .fig svg { display: block; width: 100%; height: auto; } + .fig text { font-family: var(--sans); fill: var(--fg); } + .fig-note { font-size: 13px; fill: var(--fg-soft); } + + .addr-part { font-family: var(--mono); font-size: 34px; font-weight: 700; } + .addr-at { font-family: var(--mono); font-size: 34px; fill: var(--fg-soft); } + .addr-part.user { fill: var(--accent); } + .addr-part.host { fill: #2f7d6d; } + .hint { fill: none; stroke-width: 1.5; stroke-dasharray: 4 4; } + .hint.user { stroke: var(--accent); } + .hint.host { stroke: #2f7d6d; } + + .part rect { fill: var(--bg); stroke-width: 1.5; } + .part.user rect { stroke: var(--accent); } + .part.host rect { stroke: #2f7d6d; } + .part-label { font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; } + .part.user .part-label { fill: var(--accent); } + .part.host .part-label { fill: #2f7d6d; } + .part-value { font-family: var(--mono); font-size: 15px; fill: var(--fg); } + + @media (prefers-color-scheme: dark) { + .addr-part.host { fill: #62c3ab; } + .hint.host { stroke: #62c3ab; } + .part.host rect { stroke: #62c3ab; } + .part.host .part-label { fill: #62c3ab; } + } + + .flow .lifeline { stroke: var(--line); stroke-width: 2; } + .flow .actor rect { fill: var(--bg); stroke: var(--line); stroke-width: 1.5; } + .flow .actor text { font-size: 14px; font-weight: 600; text-anchor: middle; } + .flow .actor .sub { font-size: 11px; font-weight: 400; fill: var(--fg-soft); } + .flow .actor.mine rect { fill: var(--accent-soft); stroke: var(--accent); } + + .flow .msg path { + fill: none; + stroke: var(--line); + stroke-width: 2; + marker-end: url(#arrow-idle); + } + .flow .msg text { + font-size: 12.5px; + fill: var(--fg-soft); + text-anchor: middle; + } + .flow .msg.pay path { stroke-dasharray: 6 5; } + .flow .msg.done path { stroke: var(--fg-soft); opacity: 0.55; } + .flow .msg.active path { stroke: var(--accent); stroke-width: 3; marker-end: url(#arrow-active); } + .flow .msg.active text { fill: var(--fg); font-weight: 600; } + .flow .head.idle { fill: var(--line); } + .flow .head.active { fill: var(--accent); } + + .flow .packet { + fill: var(--accent); + stroke: var(--bg); + stroke-width: 2; + transition: transform 900ms cubic-bezier(.45,.05,.35,1); + } + .flow.paused .packet { opacity: 0.45; } + + .flow-caption { + min-height: 3.2em; + margin-top: 12px; + padding: 12px 14px; + border-radius: 9px; + background: var(--bg); + border: 1px solid var(--line); + font-size: 0.95rem; + } + .flow-caption b { color: var(--accent); } + + .flow-controls { display: flex; align-items: center; gap: 8px; margin-top: 12px; flex-wrap: wrap; } + .flow-controls button { + font: inherit; + font-size: 0.9rem; + min-width: 38px; + padding: 5px 12px; + border-radius: 7px; + border: 1px solid var(--line); + background: var(--bg); + color: var(--fg); + cursor: pointer; + } + .flow-controls button:hover { border-color: var(--accent); color: var(--accent); } + .flow-dots { display: flex; gap: 6px; list-style: none; margin: 0 0 0 6px; padding: 0; } + .flow-dots button { + min-width: 0; + width: 26px; + height: 26px; + padding: 0; + border-radius: 50%; + font-size: 0.75rem; + color: var(--fg-soft); + } + .flow-dots button[aria-current="true"] { + background: var(--accent); + border-color: var(--accent); + color: #fff; + font-weight: 700; + } + @media (prefers-color-scheme: dark) { .flow-dots button[aria-current="true"] { color: #14161a; } } + + @media (prefers-reduced-motion: reduce) { + .flow .packet { transition: none; } + } + footer { margin-top: 4rem; border-top: 1px solid var(--line); @@ -193,19 +307,131 @@
- bob@example.com becomes
- GET https://example.com/.well-known/lnurlp/bob, which your server
- routes to this library.
-
Minimum and maximum sendable amounts, a description, and the callback URL to use next.
++ Nothing about a Lightning Address is new protocol — it is a naming convention on top + of plain HTTPS. The two halves of the address tell a wallet exactly which URL to open. +
+ ++ Two HTTP round trips, then a normal Lightning payment. Step through it: +
+ ++ Steps 1, 2, 3 and 6 are what this library answers. Step 4 and 5 happen against your + own node — the sats in step 7 travel from the payer straight to your wallet, never + through the library. +
+ +The pay parameters (step 2), straight from a running instance:
{
"callback": "https://example.com",
"maxSendable": 10000000000,
@@ -214,21 +440,8 @@ The server returns pay parameters
"tag": "payRequest",
"commentAllowed": false
}
-
- It calls the callback with the chosen amount in millisatoshis:
- GET /bob?amount=2000.
-
- The library requests a bolt11 invoice from the backend configured for that
- username and hands it back under pr. The wallet pays it directly —
- the library never touches funds.
-
And the invoice (step 6), with the bolt11 string under pr as LUD-06 requires:
{
"pr": "lnbc20n1p…",
"status": "OK",
@@ -237,8 +450,6 @@ Your node issues it
"disposable": false,
"error": null
}
- Requires PHP 8.3 or newer and an LNbits wallet API key.
@@ -377,5 +588,117 @@