Skip to main content

AntennaKNoBs  ·  by KK7KNB

Script your antenna. Explore it in real time by turning knobs.

AntennaKNoBs is a Python package for parametric, programmatic antenna design. You describe an antenna once as a small Python builder — its geometry expressed in terms of named parameters — and then explore the design space two ways:

  • In code, from the command line or a Python script: draw geometry, sweep a parameter, compare radiation patterns, optimize for match or gain, export a NEC deck.
  • In the browser, from a live workbench: drag a knob and watch the 3D wire model, far-field patterns, and Smith chart redraw in real time.

Its built-in engine is momwire, a new in-house set of method-of-moments engines. You can optionally add PyNEC (the battle-tested NEC2 engine) as a second backend and solve the same design both ways to trust the answer.

Test Python package Ruff Coverage


The live web workbench

It's live at app.antennaknobs.dev — open it, pick a design, and drag a knob (no install).

The workbench is the fastest way to feel a design. Pick an antenna, and its parameters appear as a panel of knobs. Drag one and every view updates live over a WebSocket: the solver re-runs and the browser redraws.

What you get:

  • A panel of knobs. Every builder parameter becomes a knob (or dropdown, or checkbox) with sensible min/max/step. Drag and the design re-solves.
  • 3D wire geometry with current visualization, viewable from three orthogonal projections (top / front / side).
  • Azimuth and elevation far-field pattern slices.
  • A Smith chart of input impedance, with optional frequency-sweep and convergence overlays.
  • Three solver slots (A / B / C) you can point at different backends and compare side by side on the same antenna, at once. The defaults are already a cross-check: B-spline d=2 (the working solver) vs. B-spline d=1 (same physics through an independent basis) vs. PyNEC.
  • A ground plane, on by default — real antennas hang over real ground, so the workbench starts there (free space is one click away). The ground is described by what it is — finite (εr=10, σ=0.002) or PEC — independent of solver; every momwire backend (and PyNEC) offers the true Sommerfeld-Norton solve and the faster reflection-coefficient method, and the solve readout reports the model that actually ran.

Live updates stay responsive because rapid knob drags are coalesced into one solve per round-trip, so the solver is never buried under stale requests.

Running it

The workbench is a FastAPI backend plus a React (Vite) frontend.

Installed (no Node needed). A wheel install bundles the pre-built frontend, so one process serves the whole app:

pip install "antennaknobs[web]"
uvicorn antennaknobs.web.server:app      # open http://127.0.0.1:8000

The backend serves the UI at / and the JSON//ws API on the same origin; /docs is the interactive API explorer.

Optional, multi-core boxes: prefix the command with OMP_WAIT_POLICY=PASSIVE GOMP_SPINCOUNT=0 to park idle solver threads between solves (~15% lower knob-drag latency). These are read once at process start, so they only work as launch env — everything else about threading the server configures itself.

Development (two terminals, hot-reload). When editing the frontend, run the Vite dev server alongside the backend so you get HMR:

# Terminal 1 — backend (from the repo root, in your .venv)
pip install -e ".[web]"
uvicorn antennaknobs.web.server:app --reload   # API on http://127.0.0.1:8000

# Terminal 2 — frontend dev server
cd src/antennaknobs/web/frontend
npm install
npm run dev                              # open http://localhost:5173

The Vite dev server proxies the API and the /ws live-solve channel to the backend on port 8000, so you only ever open http://localhost:5173. (A source checkout has no pre-built bundle, so the backend alone runs API-only until you npm run build — which writes src/antennaknobs/web/static/, the same bundle the wheel ships.)

The [web] extra pulls in uvicorn[standard], which includes the WebSocket support the live-solve channel needs — plain uvicorn fails the /ws handshake.


Two simulation backends

AntennaKNoBs can solve any design with either backend, selected per-run with --engine (CLI) or per-slot (web). Solving the same antenna two ways is the point — agreement between independent engines is your confidence check.

PyNEC momwire
What Python binding to the compiled C++ NEC2 engine In-house method-of-moments engines, pure-Python core with optional C++ accelerators
Basis NEC2 thin-wire (pulse/sinusoidal) Three bases — sinusoidal, B-spline (degree 1–2) and razor (NEC-5's razor-blade testing on a tent basis) — plus H-matrix and array-block accelerators built on the B-spline basis
Speed Very fast single-frequency solves Fast; C++ accelerators (pybind11) for assembly/quadrature, pure-Python fallback
Ground Sommerfeld–Norton finite ground (default) or the faster reflection-coefficient approximation Same two models on every solver (momwire ≥ 0.8.0): true Sommerfeld–Norton or the faster reflection-coefficient approximation; the engine API defaults to free space (the web workbench turns ground on)
Install Prebuilt wheel from the python-necpp fork release (OpenBLAS vendored) C++ accelerator built from the momwire submodule
Use it for The established reference Basis-flexible cross-validation; geometries where NEC2 reactance fails to converge

Selecting an engine (CLI):

--engine momwire                 # momwire (default), default B-spline basis
--engine momwire:sinusoidal      # NEC2-style three-term basis (cross-validator)
--engine momwire:bspline         # degree-1/2 B-spline Galerkin basis
--engine momwire:hmatrix         # B-spline + hierarchical-matrix (ACA) acceleration
--engine momwire:arrayblock      # element-aware block solver for arrays
--engine pynec                   # NEC2 via PyNEC (needs the optional pynec-accel)
--engine momwire:sinusoidal-galerkin            # three-term basis, Galerkin testing
--engine momwire:sinusoidal-galerkin-converged  # same, with the converged feed model
--engine momwire:razor-nec5      # NEC-5 formulation twin, interactive lane
--engine momwire:razor           # same, default (GL) quadrature — convergence/certification lane, not interactive

Razor (momwire:razor / momwire:razor-nec5) is a tent-basis solver tested by NEC-5's own razor-blade (mixed-potential path) rule rather than point matching or Galerkin testing — a formulation twin you can check without the licensed NEC-5 binary. razor-nec5 binds NEC-5's identified quadrature and is the interactive one (sub-second to N≈300-400 free / N≈200-400 grounded); plain razor (converged Gauss-Legendre quadrature) is 12–80× slower and exists for convergence study and certification against NEC-5 printouts, not live dragging — it can exceed an 8 GB working set by N≈800 grounded / N≈1600 free. See the solver reference for the full guidance and refusal boundary (no extended kernel, no junction/node- gap ports, no ground contact over a finite ground).

NEC-compatible vs converged feed (sinusoidal-Galerkin only): the plain sinusoidal-galerkin drives NEC's segment-wide gap — it reproduces NEC/EZNEC behaviour, including the well-known reactance drift as the mesh refines, which is what you want when cross-checking against NEC results. The -converged variant (web: the "Converged" feed-model setting on the Sin-Galerkin solver) drives a zero-width gap instead: the impedance converges to the B-spline answer, and on near-open high-Q designs (lazy_h, vbeam) it removes two to three orders of magnitude of the apparent disagreement between solver bases (momwire#213). It does not reduce the mesh a near-open design needs — budget fine mesh either way. The plain sinusoidal solver offers no such choice: a zero-width gap cannot be expressed under point-matching (momwire#212).

In Python, instantiate an engine directly:

from antennaknobs.engines import PyNECEngine, MomwireEngine
from momwire import BSplineSolver

engine = PyNECEngine(builder)
engine = MomwireEngine(builder, solver=BSplineSolver, solver_kwargs={"degree": 2})

momwire lives in its own repository and is vendored here as a git submodule; its BSplineSolver (the web workbench's default) is validated against the independent sinusoidal basis and against PyNEC, converging to NEC accuracy in ~80 segments. The H-matrix and array-block engines are newer and aimed at large arrays. PyNEC is an optional second backend — the python-necpp fork, distributed as a self-contained wheel (OpenBLAS vendored, so no SWIG/BLAS/autotools toolchain is required at install time). It is licensed GPL-2.0 and installed separately from its own release; antennaknobs (MIT) neither bundles nor depends on it, and loads it only if present.


Designing antennas in code

An antenna is a subclass of AntennaBuilder that declares named parameters and builds its wires from them. Because the geometry is computed from parameters in ordinary Python, you specify physical coordinates a minimal number of times — the rest follow by reflection and relative position. (Most antenna tools make you type six absolute coordinates per wire.)

For path-shaped geometry (loops, vees, rhombics) you can describe the walk instead of the coordinates, with the Drone 3D-turtle — see the Drone & Transform reference.

Here is the built-in Moxon beam (beams.moxon), abbreviated. Four parameters describe the rectangle; helper functions negate coordinates (rx, ry) and chain nodes into wires (build_path):

from ... import AntennaBuilder
from types import MappingProxyType


class Builder(AntennaBuilder):
    default_params = MappingProxyType(
        {
            "freq": 28.57,
            "base": 7.0,
            "halfdriver": 2.4597430629596713,   # length of one radiating side
            "aspect_ratio": 0.3646010186757216,  # short side / long side
            "tipspacer_factor": 0.07729647745945359,
            "t0_factor": 0.4078045966770739,
        }
    )

    def build_wires(self):
        eps = 0.05
        base = self.base

        long = 2 * self.halfdriver / (1 + 2 * self.aspect_ratio * self.t0_factor)
        short = self.aspect_ratio * long
        tipspacer = short * self.tipspacer_factor
        t0 = short * self.t0_factor

        def build_path(lst, ns, ex):
            return ((a, b, ns, ex) for a, b in zip(lst[:-1], lst[1:]))
        def rx(p): return -p[0], p[1], p[2]   # mirror across x
        def ry(p): return p[0], -p[1], p[2]   # mirror across y

        S = (short / 2, eps, base)
        A = (S[0], long / 2, base)
        B = (A[0] - t0, A[1], base)
        C = (B[0] - tipspacer, B[1], base)
        D = rx(A)
        E, F, G, H, T = ry(D), ry(C), ry(B), ry(A), ry(S)

        n_seg0, n_seg1 = 21, 1
        tups = []
        tups.extend(build_path([S, A, B], n_seg0, None))
        tups.extend(build_path([C, D, E, F], n_seg0, None))
        tups.extend(build_path([G, H, T], n_seg0, None))
        tups.append((T, S, n_seg1, 1 + 0j))   # the driven segment
        return tups

The top-level package re-exports the workhorse functions, so a full design-explore-compare loop is a short script. This optimizes an inverted-V dipole at several heights and overlays the resulting patterns:

import antennaknobs as ant
from antennaknobs.designs.dipoles.invvee import Builder

p = dict(Builder.default_params)
bounds = ((p['length_factor'] * .8, p['length_factor'] * 1.25), (0, 60))

builders = (
    ant.optimize(
        Builder(dict(p, base=base)),
        ['length_factor', 'angle_deg'], z0=50, bounds=bounds,
    )
    for base in [5, 6, 7, 8]
)

ant.compare_patterns(builders)

Command-line usage

Everything is under python -m antennaknobs <subcommand>. Designs are named family.name (with an optional :variant) — run list to see them all.

# Draw a Moxon's wire geometry to a file
python -m antennaknobs draw --builder beams.moxon --fn moxon.png

# Sweep frequency and plot impedance on a Smith chart
python -m antennaknobs sweep --builder beams.moxon --param freq \
    --use_smithchart --npoints 21 --fn moxon_smith.png

# Capture a sweep from an attached NanoVNA (needs the [vna] extra)
python -m antennaknobs capture --out bench_10m.s1p --start 28 --stop 29

# Overlay a measured NanoVNA .s1p sweep on the modeled SWR curve
python -m antennaknobs sweep --builder dipoles.invvee --swr \
    --range 28.0 29.0 --npoints 21 --measured bench_10m.s1p

# Far-field pattern of a Yagi, solved with momwire
python -m antennaknobs pattern --builder beams.yagi --engine momwire:triangular

# Overlay patterns of three beams
python -m antennaknobs compare_patterns \
    --builders beams.moxon beams.hexbeam beams.yagi --fn beams.png

# Cross-check one design across two backends
python -m antennaknobs compare_patterns \
    --builders beams.moxon beams.moxon --engines pynec momwire:bspline --fn check.png

# Optimize length and arm angle of an inverted-V dipole for a 50 Ω match
python -m antennaknobs optimize --builder dipoles.invvee \
    --params length_factor angle_deg

# Export a NEC2 card deck for use in external tools
python -m antennaknobs export --builder beams.hexbeam --out hexbeam.nec

# List the available designs (optionally filter)
python -m antennaknobs list
python -m antennaknobs list dipole

Shared flags: --engine (backend, see above), --ground (free | pec | finite | finite:<eps_r>,<sigma>), --builder/--builders, and --fn (save to file instead of showing on screen).

Below is a typical far-field plot produced by the pattern/compare_patterns commands:

Radiation pattern

Available designs

Roughly 70 built-in designs across nine families — run python -m antennaknobs list for the authoritative list:

Family Examples
dipoles invvee, folded_invvee, ocf_dipole, koch_dipole, dipole_turnstile
beams moxon, hexbeam, yagi, hb9cv
loops quad, delta_loop, diamond_loop, horizontal_loop, bisquare
verticals vertical, jpole, inverted_l, bobtail, four_square, bruce
arrays yagiarray, moxonarray, invveearray, bowtiearray, delta_looparray
multiband fandipole, trap_dipole, hexbeam_5band, twoband_fan_dipole
broadband discone, g5rv, lpda, t2fd
wire sterba, rhombic, vbeam, w8jk, zepp, lazy_h, longwire
specialty hentenna, bowtie, helix, hourglass

User-authored designs (in the user.* namespace) appear here too; filter with list --builtin-only / list --user-only. Drop a Python file in ~/.antennaknobs/designs/ and it shows up in the workbench — see Writing designs with Claude Code for the contract and how to have Claude Code write one from a plain-language description.


Install

Docker (nothing but Docker required)

docker run --rm -p 8000:8000 stevenmburns/antennaknobs:latest
# -> the full web workbench at http://localhost:8000

Published on every release. See DOCKER.md for the compose file, mounting your own designs into the container, and adding the optional NEC2 engine.

From PyPI (prebuilt wheels — no toolchain)

antennaknobs and its C++ engine momwire are published to PyPI with prebuilt wheels, so a plain install needs no compiler:

python3 -m venv .venv && source .venv/bin/activate
pip install --upgrade pip

# antennaknobs + the web workbench; momwire (the engine) comes along as a dep
pip install "antennaknobs[web]"

Optionally, add the NEC2 solver (PyNEC) as an alternative to momwire:

# optional NEC2 solver (Linux / Windows / macOS-arm64 wheels)
pip install "pynec-accel>=1.7.4.post2"

Then launch the workbench with uvicorn antennaknobs.web.server:app (see Running it). On macOS, brew install libomp is required — the momwire and pynec-accel wheels link Homebrew's OpenMP runtime (and share it, so cross-engine use is fully multithreaded; details under macOS).

The sections below build from source instead (a development checkout, or a platform without prebuilt wheels).

Ubuntu (22.04 / 24.04)

PyNEC installs as a prebuilt wheel, so no SWIG/BLAS/autotools toolchain is needed; only the momwire C++ accelerator compiles from source (hence g++).

1. System dependencies

sudo apt-get update
sudo apt-get install \
    python3 python3-pip python3-venv python3-dev \
    g++ build-essential git

2. Clone and create a virtual environment

git clone https://github.com/stevenmburns/antennaknobs
cd antennaknobs
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install setuptools numpy scipy pytest matplotlib

3. Install momwire (the engine)

# momwire: a git submodule; its C++ accelerator builds from source.
pip install pybind11
git submodule update --init momwire
pip install --no-build-isolation -e ./momwire

The submodule pointer tracks the exact momwire release the pyproject pins. If it ever drifts behind the pin, step 4 below silently replaces your editable momwire with the PyPI wheel (pip resolving momwire==X) and edits under momwire/ stop taking effect — verify with python -c "import momwire; print(momwire.__file__)", which must point into the checkout, and re-run this step after git submodule update --remote momwire if it doesn't.

3b. (Optional) Install PyNEC for cross-validation

PyNEC is an optional second backend — GPL-2.0, installed separately from its own release, and never bundled with or required by antennaknobs. Skip it and momwire is still fully functional; install it only if you want to cross-check against NEC2.

# The fork is published to PyPI as `pynec-accel` (a distinct name from upstream
# PyNEC/pynec, whose builds are broken on current Python; the import name stays
# `import PyNEC`). Its wheels vendor OpenBLAS + libgfortran.
#
# Use >= 1.7.4.post2: earlier builds vendored their own libgomp, which clashes
# with momwire's system libgomp via a static-TLS limit and silently knocks
# momwire's C++ accelerator onto its slow pure-Python path whenever both backends
# load in one process. post2 binds the system libgomp instead (universal on glibc
# Linux — the GCC OpenMP runtime).
pip install "pynec-accel>=1.7.4.post2"

4. Install AntennaKNoBs

pip install -e ".[test]"         # core + test deps (pytest, the web test client)
# or  pip install -e ".[web]"    # just the web workbench, no test extras
# or  pip install -e .           # library only

5. Run the tests

pytest -vv --durations=0 -- tests/

(The [test] extra above is what makes this step work from a clean clone — it pulls in pytest, the [web] server deps, and httpx2 for the web-server tests' TestClient.)

The authoritative, always-tested version of this whole sequence is the CI workflow at .github/workflows/test.yml — it installs both engines and runs the suite on every push. If anything here drifts, that file is the source of truth.

macOS

Tested on Apple Silicon (arm64), macOS 14+. The momwire C++ accelerator compiles from source against Homebrew's OpenMP runtime (libomp); PyNEC installs as a prebuilt wheel. CI only runs Ubuntu, so the Ubuntu sequence above is the source of truth — the steps below are the same with macOS system packages.

1. System dependencies

xcode-select --install              # clang/clang++ + git (skip if already installed)
brew install python git libomp      # libomp = the OpenMP runtime the momwire accelerator links

2. Clone and create a virtual environment. Use a venv — on macOS it is effectively required, not just good hygiene: Homebrew's Python is marked externally managed (PEP 668), so pip install into it fails with an error: externally-managed-environment. A venv sidesteps that and keeps the project's dependencies off your system Python.

git clone https://github.com/stevenmburns/antennaknobs
cd antennaknobs
python3 -m venv .venv
source .venv/bin/activate         # re-run this in each new shell before using the project
pip install --upgrade pip setuptools wheel
pip install numpy scipy pytest matplotlib

3. Install momwire (the engine) — same as Ubuntu:

pip install pybind11
git submodule update --init momwire
pip install --no-build-isolation -e ./momwire

The build finds Homebrew's libomp at /opt/homebrew/opt/libomp, the Apple Silicon default. On an Intel Mac, Homebrew lives under /usr/local, so point the build there with LIBOMP_PREFIX:

LIBOMP_PREFIX=/usr/local/opt/libomp pip install --no-build-isolation -e ./momwire

If the accelerator fails to build for any reason, momwire still installs and runs in its slower pure-Python mode.

3b. (Optional) Install PyNEC for cross-validation

The same optional GPL-2.0 second backend as on Linux. The fork ships prebuilt macOS wheels for Apple Silicon (arm64), macOS 14+, Python 3.10–3.14 only — there are no Intel-Mac wheels, so on an Intel Mac skip PyNEC and use momwire alone.

pip install "pynec-accel>=1.7.4.post2"

With pynec-accel ≥ 1.7.4.post2 and momwire ≥ 0.2.1, neither wheel vendors its own libomp — both link Homebrew's by absolute path, so a process that loads both (any cross-engine run, including the tests) shares a single OpenMP runtime and stays fully multithreaded, with no env vars. That shared runtime is why brew install libomp is required.

Older macOS wheels each bundled a private libomp; two copies in one process abort with OMP: Error #15 (or, with KMP_DUPLICATE_LIB_OK=TRUE, deadlock). If you're pinned to a pre-1.7.4.post2 pynec-accel or pre-0.2.1 momwire, the stopgap is export KMP_DUPLICATE_LIB_OK=TRUE and export OMP_NUM_THREADS=1 before any cross-engine run — at the cost of a single-threaded accelerator.

4. Install AntennaKNoBs and 5. Run the tests — identical to the Ubuntu steps:

pip install -e ".[test]"
pytest -vv --durations=0 -- tests/

(For the web workbench's frontend dev server, also brew install node.)


Acknowledgments

Most of this codebase — the AntennaBuilder framework, the design catalog, the momwire engine bindings, the web workbench, and these docs — was written with Claude Code, Anthropic's agentic coding tool, working from KK7KNB's direction and antenna-engineering judgment.

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

antennaknobs-0.62.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

antennaknobs-0.62.0-py3-none-any.whl (793.8 kB view details)

Uploaded Python 3

File details

Details for the file antennaknobs-0.62.0.tar.gz.

File metadata

  • Download URL: antennaknobs-0.62.0.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for antennaknobs-0.62.0.tar.gz
Algorithm Hash digest
SHA256 b5213758c3c2d9cc5a68ad6edf383087f1aab825e542811bcecf185ef1c7b670
MD5 e25a2a1f9656627297e35a9927081c0c
BLAKE2b-256 6c7917b385b7f8d2071219af4deb40f8436824ad1fe07b60f5a0d8e87701a914

See more details on using hashes here.

Provenance

The following attestation bundles were made for antennaknobs-0.62.0.tar.gz:

Publisher: publish.yml on stevenmburns/antennaknobs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file antennaknobs-0.62.0-py3-none-any.whl.

File metadata

  • Download URL: antennaknobs-0.62.0-py3-none-any.whl
  • Upload date:
  • Size: 793.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for antennaknobs-0.62.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d41b585eb76444e39a85098b2dc4b0a38bee6578c61bb2e969e9e88ab0c72c64
MD5 ec04a201586cc1f0642524d0d031a64e
BLAKE2b-256 1f5c09befa3a7c9164e92dc44fef2c76113418e545303643e96af4037905b44d

See more details on using hashes here.

Provenance

The following attestation bundles were made for antennaknobs-0.62.0-py3-none-any.whl:

Publisher: publish.yml on stevenmburns/antennaknobs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.70.0

2 files

0.69.0

2 files

0.68.0

2 files

0.67.0

2 files

0.66.0

2 files

0.65.0

2 files

0.64.0

2 files

0.63.0

2 files

This release

0.62.0 This release

2 files

0.61.0

2 files

0.60.0

2 files

0.59.0

2 files

0.58.0

2 files

0.57.0

2 files

0.56.0

2 files

0.55.0

2 files

0.54.0

2 files

0.53.0

2 files

0.52.0

2 files

0.51.0

2 files

0.50.0

2 files

0.49.0

2 files

0.48.0

2 files

0.47.0

2 files

0.46.0

2 files

0.45.0

2 files

0.44.0

2 files

0.43.0

2 files

0.42.0

2 files

0.41.0

2 files

0.40.0

2 files

0.39.0

2 files

0.38.0

2 files

0.37.0

2 files

0.36.1

2 files

0.36.0

2 files

0.35.2

2 files

0.35.1

2 files

0.35.0

2 files

0.34.1

2 files

0.34.0

2 files

0.33.0

2 files

0.32.0

2 files

0.31.0

2 files

0.30.0

2 files

0.29.0

2 files

0.28.0

2 files

0.27.1

2 files

0.27.0

2 files

0.26.0

2 files

0.25.0

2 files

0.24.0

2 files

0.23.0

2 files

0.22.1

2 files

0.22.0

2 files

0.21.0

2 files

0.20.0

2 files

0.19.0

2 files

0.18.0

2 files

0.17.0

2 files

0.16.0

2 files

0.15.0

2 files

0.14.0

2 files

0.13.2

2 files

0.13.1

2 files

0.13.0

2 files

0.12.0

2 files

0.11.0

2 files

0.10.0

2 files

0.9.0

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page