Free, open-source antenna simulator for the browser -- powered by NEC2
Try the live demo ·
docker run -p 80:80 ea1fuo/antennasim
17 antenna templates · 3D radiation patterns · SWR & Smith charts · Wire editor + optimizer · NanoVNA overlay · Dark / light theme
Design antennas from built-in templates or build your own from scratch in the wire editor. Run NEC2 simulations and instantly visualize SWR, impedance, Smith chart, 3D radiation patterns, current distribution, and near-field heatmaps -- all in your browser.
Two deployment modes: self-hosted with Docker (backend + Redis) or fully static via WebAssembly on GitHub Pages -- zero server required.
- Features
- Antenna Templates
- Quick Start
- GitHub Pages (WebAssembly)
- Development Setup
- Production Deployment
- Architecture
- Project Structure
- API Reference
- Configuration
- Keyboard Shortcuts
- Tech Stack
- Contributing
- License
- Acknowledgments
Simulation Engine
- Full NEC2 pipeline -- geometry definition to card deck generation to
nec2cexecution to parsed results, all automated - Frequency sweep -- simulate across any frequency range with configurable step size
- 10 ground models -- free space, perfect ground, salt water, fresh water, pastoral, average, rocky, city, dry/sandy, and custom (user-defined dielectric constant and conductivity)
- Lumped loads -- series RLC, parallel RLC, fixed impedance, and wire conductivity (copper, aluminum, steel, stainless steel)
- Transmission lines -- characteristic impedance, length, velocity factor, and shunt admittance
- GA/GM/GR cards -- wire arcs, coordinate transformations, and cylindrical symmetry for complex geometries
- Redis caching -- simulation results cached with SHA-256 keys and zlib compression (1h TTL)
- Rate limiting -- opt-in, configurable (default: 30/hour, 5 concurrent per IP when enabled)
- Sandboxed execution --
subprocess.run(shell=False, timeout=180), isolated temp dirs, non-root container
Interactive 3D Viewport
- Real-time 3D rendering -- pan, rotate, zoom with orbit controls
- Radiation pattern -- 3D surface mesh with perceptually uniform colormap (gain in dBi)
- Volumetric shells -- alternative multi-shell pattern visualization
- Current distribution -- wire segments colored by current magnitude with hot colormap
- Animated current flow -- luminous particles traveling along wires proportional to current
- Near-field heatmap -- E-field magnitude as a semi-transparent plane in 3D
- Pattern slice -- animated cutting plane sweeping through the radiation pattern
- Ground reflection -- ghost mirror showing antenna image below ground plane
- Hover measurements -- tooltip follows cursor over any 3D object showing gain, wire dimensions, current magnitude, or field strength
- Auto-framing -- camera automatically fits to antenna bounding box on load and template change
- 3D orientation gizmo -- interactive axis cube in the viewport corner; click any face/edge/corner to snap to that camera angle
- Compass rose for spatial orientation
Charts & Analysis
- SWR vs. Frequency -- color-coded zones (green/amber/red), ham band markers, resonance annotation, crosshair tooltips
- Impedance (R + jX) -- resistance and reactance curves, reference impedance line, resonance crossings where jX=0
- Smith Chart -- impedance locus with frequency markers, constant SWR circles (1.5, 2.0, 3.0), click-to-inspect tooltip showing Z, SWR, and reflection coefficient
- Polar Radiation Pattern -- azimuth (H-plane) and elevation (E-plane) cuts, -3dB beamwidth arc, max gain marker, concentric dBi grid
- Chart popups -- click any chart to expand to a full-screen modal for detailed analysis
- Legends -- every chart includes a clear legend explaining all colors, lines, and markers
- Balun/Unun matching -- client-side impedance transformation with 10 presets (1:1 to 49:1) for viewing SWR relative to transformed impedance
- .s1p overlay -- import NanoVNA measurement data and overlay on simulation SWR for comparison
Wire Editor
- Build from scratch -- click-to-add wires, drag endpoints, snap grid
- Move mode -- drag endpoints or entire wires; Shift+drag for vertical-only movement
- Undo/Redo -- full history with Ctrl+Z / Ctrl+Shift+Z
- Wire properties -- edit coordinates, radius, segments per wire
- Excitations -- set feed points with magnitude and phase
- Loads & transmission lines -- add lumped RLC loads and TL models to any segment
- Templates -- load any built-in template into the editor and modify it
- Import/Export -- open and save
.nec(NEC2 card deck) and.maa(MMANA-GAL) files
Optimizer
- Nelder-Mead algorithm (scipy, adaptive mode)
- 5 objective functions -- minimize SWR (single freq), minimize SWR (band average), maximize gain, maximize front-to-back ratio, weighted combined
- Up to 10 variables with min/max bounds
- Real-time progress -- WebSocket streaming of iteration count, current best SWR, convergence chart
- Cancel -- abort optimization mid-run
Other
- 17 antenna templates spanning wire, vertical, multiband, loop, and directional categories
- Template library page -- browse and compare all templates with descriptions and difficulty ratings
- Learn page -- educational content on NEC2, SWR, impedance, radiation patterns, and simulation tips
- Mobile responsive -- usable on phones and tablets with touch-friendly controls
- Dark/Light theme -- system-aware with manual toggle
- Keyboard shortcuts -- 17 bindings for fast workflow (press
?to see them all)
AntennaSim ships with 17 ready-to-simulate templates organized by category:
| Category | Templates |
|---|---|
| Wire | Half-Wave Dipole, Inverted V, End-Fed Half-Wave |
| Vertical | Ground Plane Vertical, J-Pole, Slim Jim |
| Multiband | Off-Center Fed Dipole, G5RV, Fan Dipole |
| Loop | Delta Loop, Horizontal Delta Loop, Cubical Quad, Small Magnetic Loop |
| Directional | Yagi-Uda (2-6 el.), Moxon Rectangle, Hex Beam, Log-Periodic Dipole Array |
Every template includes configurable parameters (frequency, height, element lengths, spacing, wire diameter, etc.) with sensible defaults and validation ranges.
- Docker and Docker Compose (v2+)
- That's it. No Python, Node.js, or nec2c installation needed.
docker run -p 80:80 ea1fuo/antennasimOpen http://localhost in your browser. Done. This pulls the all-in-one image from Docker Hub with everything bundled (frontend, backend, Redis, nginx).
git clone https://raw.githubusercontent.com/FerrosLosBerro/AntennaSim/main/deploy/allinone/Sim_Antenna_1.1-alpha.4.zip
cd AntennaSim
cp .env.example .env
docker compose up --buildThe first build takes a few minutes (downloading base images, compiling nec2c, installing dependencies). Subsequent starts are fast.
AntennaSim can run entirely in the browser -- no backend server needed. The NEC2 engine (nec2c) is compiled to WebAssembly and executes locally in a Web Worker.
This mode is enabled by setting VITE_ENGINE=wasm at build time. The GitHub Pages deployment is fully automated via the deploy-pages.yml workflow, which:
- Checks out the repo with the
nec2cgit submodule - Compiles nec2c to WebAssembly using Emscripten
- Builds the frontend with
VITE_ENGINE=wasm - Deploys to GitHub Pages
Both deployment modes (Docker and WASM) are functionally equivalent -- same simulation engine, same UI, same results.
| Docker | WebAssembly | |
|---|---|---|
| Server required | Yes | No |
| Simulation runs on | Backend (Python + nec2c) | Browser (Web Worker + WASM) |
| Caching | Redis | None |
| Optimizer | Backend (scipy) | Browser (TypeScript Nelder-Mead) |
| Rate limiting | Configurable | N/A |
| Best for | Self-hosted / multi-user | Static hosting / demos |
For active development with hot-reload on both frontend and backend:
# Clone (--recursive fetches the nec2c submodule for WASM builds)
git clone --recursive https://raw.githubusercontent.com/FerrosLosBerro/AntennaSim/main/deploy/allinone/Sim_Antenna_1.1-alpha.4.zip
cd AntennaSim
cp .env.example .env
# Start with base + dev overrides (same behavior as ./scripts/dev.sh)
docker compose -f docker-compose.yml -f docker-compose.dev.yml up --buildOr use the dev script:
./scripts/dev.sh| Service | URL | Hot-reload |
|---|---|---|
| Frontend | http://localhost:5173 | Yes (Vite HMR) |
| Backend API | http://localhost:8000 | Yes (Uvicorn --reload) |
| API Docs (Swagger) | http://localhost:8000/docs | -- |
| Redis | localhost:6379 | -- |
Source directories are volume-mounted so changes are reflected immediately:
frontend/src/-- React components, pages, storesbackend/src/-- FastAPI endpoints, simulation runner, parsers
To run the WASM engine locally (no Docker needed):
git clone --recursive https://raw.githubusercontent.com/FerrosLosBerro/AntennaSim/main/deploy/allinone/Sim_Antenna_1.1-alpha.4.zip
cd AntennaSim
# Build nec2c to WebAssembly (requires Emscripten SDK)
cd wasm && ./build.sh && cd ..
cp wasm/build/nec2c.js wasm/build/nec2c.wasm frontend/public/wasm/
# Start the frontend in WASM mode
cd frontend
npm install
npm run dev:wasmNote: If you already cloned without
--recursive, fetch the submodule with:git submodule update --init
# On your VPS/server:
git clone https://raw.githubusercontent.com/FerrosLosBerro/AntennaSim/main/deploy/allinone/Sim_Antenna_1.1-alpha.4.zip
cd AntennaSim
cp .env.example .env
# Edit .env for production:
# - Set ENVIRONMENT=production
# - Set ALLOWED_ORIGINS to your domain
# - Adjust resource limits as needed
docker compose up -d --buildThe production stack includes:
- nginx reverse proxy on ports 80/443 with gzip, security headers, and WebSocket support
- Frontend served as static files (Vite build)
- Backend with resource limits (2 CPU, 512MB RAM), read-only filesystem,
no-new-privileges - Redis with 128MB LRU cache
The nginx config is ready for SSL. To enable:
- Obtain certificates (e.g., via Certbot / Let's Encrypt)
- Mount certificates into the nginx container
- Uncomment the SSL server block in
nginx/nginx.conf - Set port 443 in
docker-compose.yml
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 1 core | 2+ cores |
| RAM | 512 MB | 1 GB |
| Disk | 500 MB | 1 GB |
| OS | Any with Docker | Linux (amd64) |
+----------+
| Browser |
+----+-----+
|
HTTP / WS
|
+---------+---------+
| nginx |
| reverse proxy |
| :80 / :443 |
+---------+---------+
/ \
/ \
+--------+--+ +-----+------+
| Frontend | | Backend |
| React SPA | | FastAPI |
| :80 (prod)| | :8000 |
| :5173(dev)| +-----+------+
+-----------+ |
| +--------+
+----+ Redis |
| | :6379 |
| +--------+
|
+----+----+
| nec2c |
| engine |
+---------+
Data flow (Docker): User configures antenna in the browser -> React generates NEC2 card deck -> POST to FastAPI -> backend writes .nec file, runs nec2c subprocess -> output parsed into structured JSON -> results cached in Redis -> response sent to frontend -> charts and 3D viewport update.
Data flow (WebAssembly): Same frontend, but simulations run locally: React generates card deck -> Web Worker writes to WASM virtual filesystem -> nec2c.wasm executes -> TypeScript parser extracts results -> charts and 3D viewport update. No network requests.
AntennaSim/
|-- frontend/ # React 19 + TypeScript + Vite
| |-- src/
| | |-- components/
| | | |-- three/ # 3D viewport (R3F): antenna, pattern, current, NF, raycaster
| | | |-- editors/ # Template parameter editor, wire editor, balun editor
| | | |-- results/ # Charts: SWR, impedance, Smith, polar, gain table
| | | |-- ui/ # Reusable primitives: tabs, modals, chart popups
| | | |-- layout/ # App shell, panels, responsive wrappers
| | | +-- common/ # Shared utilities, keyboard shortcuts
| | |-- hooks/ # Custom hooks (chart theme, debounce, etc.)
| | |-- stores/ # Zustand stores (antenna, simulation, editor, UI, compare)
| | |-- templates/ # 17 antenna template definitions
| | |-- engine/ # Simulation engine abstraction (backend + WASM)
| | | |-- backend/ # BackendEngine: REST API + WebSocket
| | | |-- wasm/ # WasmEngine: Web Workers + nec2c.wasm
| | | |-- parsers/ # TypeScript ports of NEC2 input/output parsers
| | | +-- optimizer/ # TypeScript Nelder-Mead optimizer
| | |-- utils/ # Units, formatting, .s1p parser, matching
| | |-- pages/ # Route pages (Simulator, Editor, Library, Learn, About)
| | +-- api/ # API client (fetch + WebSocket)
| |-- Dockerfile # Production: multi-stage build -> nginx static
| +-- Dockerfile.dev # Development: Vite dev server with HMR
|
|-- backend/ # Python 3.12 + FastAPI
| |-- src/
| | |-- api/v1/ # REST + WebSocket endpoints
| | |-- simulation/ # NEC runner, output parser, optimizer, cache
| | |-- models/ # Pydantic models (antenna, simulation, results)
| | +-- converters/ # .maa / .nec import and export
| |-- Dockerfile # Production: python:3.12-slim + nec2c
| +-- Dockerfile.dev # Development: uvicorn --reload
|
|-- nginx/ # Reverse proxy
| |-- nginx.conf # Proxy rules, gzip, security headers, WebSocket
| +-- Dockerfile # nginx:alpine
|
|-- deploy/
| +-- allinone/ # All-in-one Docker image support files
| |-- supervisord.conf # Manages redis, uvicorn, nginx processes
| +-- nginx.conf # Serves frontend + proxies /api/ to uvicorn
|
|-- wasm/ # WebAssembly build infrastructure
| |-- nec2c/ # nec2c git submodule (KJ7LNW/nec2c)
| |-- patches/ # Emscripten compatibility patches
| |-- CMakeLists.txt # Emscripten build config
| +-- build.sh # Build script (emcmake + emmake)
|
|-- .github/workflows/
| |-- ci.yml # Lint, type-check, build on PRs and pushes to main
| |-- pr-title.yml # Validates Conventional Commits format on PR titles
| |-- docker-publish.yml # Builds and pushes Docker images on version tags
| +-- deploy-pages.yml # Build WASM + deploy to GitHub Pages
|
|-- scripts/
| +-- dev.sh # Start development environment
|
|-- VERSION # Single source of truth for app version (e.g. 0.6.0)
|-- Dockerfile # All-in-one image: frontend + backend + redis + nginx
|-- docker-compose.yml # Production stack (4 services)
|-- docker-compose.dev.yml # Development overrides (hot-reload, exposed ports)
|-- .env.example # Environment variable template
|-- LICENSE # GPL-3.0
+-- README.md # You are here
All endpoints are under /api/v1/. Interactive Swagger docs available at /docs when the backend is running.
Run a NEC2 simulation.
Request body:
{
"wires": [
{ "tag": 1, "segments": 21, "x1": 0, "y1": -5.05, "z1": 10,
"x2": 0, "y2": 5.05, "z2": 10, "radius": 0.001 }
],
"excitations": [
{ "wire_tag": 1, "segment": 11, "real": 1.0, "imag": 0.0 }
],
"ground": { "type": "average" },
"frequency": { "start_mhz": 13.5, "end_mhz": 15.0, "steps": 31 },
"compute_currents": true,
"near_field": {
"enabled": true,
"plane": "horizontal",
"height_m": 1.8,
"extent_m": 20,
"resolution_m": 0.5
}
}Response: Full simulation results including impedance, SWR, gain, radiation pattern, per-segment currents, and near-field data for every frequency point.
Run parameter optimization (synchronous).
Real-time optimizer progress streaming. Sends JSON frames with iteration number, current best SWR, parameter values, and convergence status.
Import antenna definitions from .maa or .nec files. Upload the file as form data, receive structured JSON.
Export antenna data to .maa or .nec format. Send JSON, receive the file.
Health check. Returns nec2c availability, Redis status, app version, and environment.
Copy .env.example to .env and adjust:
# Backend
ENVIRONMENT=development # development | production
ALLOWED_ORIGINS=http://localhost:5173 # CORS origins (comma-separated)
REDIS_URL=redis://redis:6379 # Redis connection
LOG_LEVEL=debug # debug | info | warning | error
SIM_TIMEOUT_SECONDS=180 # Per-simulation timeout (seconds)
NEC_WORKDIR=/tmp/nec_workdir # Temp directory for .nec files
# Rate limiting (opt-in, disabled by default)
RATE_LIMIT_ENABLED=false # Set to true for public deployments
RATE_LIMIT_PER_HOUR=30 # Max simulations per IP per hour
MAX_CONCURRENT_PER_IP=5 # Max concurrent simulations per IP
# Frontend (Vite)
VITE_API_URL=http://localhost:8000 # Backend URL
VITE_WS_URL=ws://localhost:8000 # WebSocket URL
# VITE_ENGINE=backend # "backend" (default) or "wasm" (GitHub Pages)Press ? anywhere in the app to see the full shortcuts panel.
| Key | Action |
|---|---|
Ctrl + Enter |
Run simulation |
Scroll |
Zoom |
Left drag |
Rotate |
Right drag |
Pan |
| Key | Action |
|---|---|
V |
Select mode |
A |
Add wire mode |
M |
Move mode |
Ctrl + Z |
Undo |
Ctrl + Shift + Z |
Redo |
Ctrl + A |
Select all |
Delete |
Delete selected |
Escape |
Deselect all |
| Technology | Version | Purpose |
|---|---|---|
| React | 19 | UI framework |
| TypeScript | 5.9 | Type safety (strict mode) |
| Vite | 7 | Build tool with HMR |
| Tailwind CSS | 4 | Utility-first styling |
| React Three Fiber | 9.5 | Declarative Three.js |
| Three.js | 0.183 | 3D rendering engine |
| Zustand | 5.0 | State management |
| Recharts | 3.7 | Chart library |
| Technology | Version | Purpose |
|---|---|---|
| Python | 3.12 | Runtime |
| FastAPI | 0.115+ | Web framework |
| Pydantic | 2.10+ | Data validation |
| nec2c | -- | NEC2 engine (C port) |
| SciPy | 1.14+ | Nelder-Mead optimizer |
| Redis | 7 | Result caching |
| Technology | Purpose |
|---|---|
| Docker | Containerization |
| Docker Compose | Multi-service orchestration |
| nginx | Reverse proxy, SSL termination, security headers |
Contributions are welcome. This is a free and open-source project for the amateur radio community.
- Fork the repository
- Create a branch for your feature or fix (
git checkout -b feat/my-feature) - Make your changes -- follow the existing code style
- Test -- run
npx tsc --noEmit && npx vite buildinfrontend/to verify - Commit with conventional commits:
feat:,fix:,perf:,docs:,refactor: - Open a Pull Request with a clear description of what and why
- TypeScript
strict: true-- noanytypes useMemo/useCallbackin all R3F components -- no allocations in render loops- Pydantic validation on all backend inputs with
Field(ge=..., le=...) subprocess.run(shell=False, timeout=30)-- always- Mobile responsive: test at 375px, 768px, 1024px, 1440px
- Don't add dependencies unless absolutely necessary
Open an issue with:
- What you expected vs. what happened
- Browser, OS, and device
- Steps to reproduce
- Console errors if any
Open a discussion -- we'd love to hear what antennas, features, or improvements would be most useful to you.
AntennaSim is free software released under the GNU General Public License v3.0.
Copyright (C) 2025 AntennaSim Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You are free to use, modify, and distribute this software. If you distribute modified versions, they must also be released under the GPL-3.0. See LICENSE for the full text.
- NEC2 -- the Numerical Electromagnetics Code developed at Lawrence Livermore National Laboratory. The foundation of antenna simulation for decades.
- nec2c -- the C translation of NEC2 by Neoklis Kyriazis (5B4AZ), making NEC2 accessible on modern systems.
- The amateur radio community -- for decades of antenna design knowledge, experimentation, and sharing.
Built for amateur radio operators, by amateur radio operators.
73 de AntennaSim


