Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ca39754
Update icon with Affinity logo
jcallaham Jan 22, 2026
3b9285d
Fix brand area
jcallaham Jan 22, 2026
6050d9f
Added basic diagram templates
jcallaham Jan 22, 2026
f417305
Add disturbance to templates
jcallaham Jan 22, 2026
1615550
Fix centering bug
jcallaham Jan 22, 2026
82c5ba6
Fix failing frontend test
jcallaham Jan 22, 2026
9d4f598
Fix deserialization bug in IOMarker
jcallaham Jan 22, 2026
85e0c7e
Add template constructor
jcallaham Jan 22, 2026
1381530
Fix IOMarker label bug
jcallaham Jan 22, 2026
15b4f6a
Condensed extraction tests
jcallaham Jan 24, 2026
3db2559
Migrate templates to static JSON
jcallaham Jan 24, 2026
52b5b00
Dynamic template loader
jcallaham Jan 24, 2026
60816a8
Rename TF parameters
jcallaham Jan 24, 2026
f82f42a
Improved Python parameter editing UX (#4)
jcallaham Jan 24, 2026
f2711b2
Restructure core concept docs
jcallaham Jan 24, 2026
c5d77ba
Finish editor docs page
jcallaham Jan 24, 2026
7f24442
Fix rendering viewport positioning/sizing
jcallaham Jan 24, 2026
c890f55
Fix rendering bugs
jcallaham Jan 24, 2026
9920008
Fix fit-to-view
jcallaham Jan 24, 2026
3d7c713
Fix parameter panel double-click issues
jcallaham Jan 24, 2026
3f95e03
Add templates.md and .png examples
jcallaham Jan 24, 2026
293a0d1
Add cruise control example
jcallaham Jan 25, 2026
4ac2e56
Finish cruise control example
jcallaham Jan 25, 2026
68007c4
Add Diagram.__str__
jcallaham Jan 25, 2026
2bdd299
Fix scalar num/den handling in algebraic loop detection
jcallaham Jan 26, 2026
67591d4
Fix auto theme code blocks
jcallaham Jan 26, 2026
4a0efa9
Add test for failing re-evaluation
jcallaham Jan 27, 2026
722ed22
Enable deployment
jcallaham Jan 30, 2026
b4a7a4f
Failing backend test
jcallaham Jan 30, 2026
e207b0b
Run prettier
jcallaham Jan 30, 2026
a25ca4e
Linting and formatting
jcallaham Jan 30, 2026
3882c2a
Remove test that pointed to local/ file
jcallaham Jan 30, 2026
7506b03
Fix JS linting errors
jcallaham Jan 30, 2026
1d0d08f
Fix licensing headers
jcallaham Jan 30, 2026
f99cbd8
Fix CI failures
jcallaham Jan 30, 2026
1639bad
Activate virtual environment for docs build
jcallaham Jan 30, 2026
74a3bfe
Remove performance tests
jcallaham Jan 30, 2026
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
9 changes: 3 additions & 6 deletions .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ jobs:
- name: Install dependencies
run: |
uv sync --all-extras --dev
source .venv/bin/activate
python -m ipykernel install --user --name lynx

- name: Build HTML documentation
run: |
Expand All @@ -84,13 +86,8 @@ jobs:
with:
path: docs/_build/html

# DEPLOYMENT DISABLED: Repository is currently private
# To enable deployment when ready:
# 1. Make repository public (Settings → Danger Zone → Change visibility)
# 2. Enable GitHub Pages (Settings → Pages → Source: "GitHub Actions")
# 3. Change the condition below to: if: github.ref == 'refs/heads/main' && github.event_name == 'push'
deploy:
if: false # DISABLED - Remove this line to enable deployment
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: build
runs-on: ubuntu-latest
environment:
Expand Down
26 changes: 14 additions & 12 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later

# Frontend build output
js/dist/
js/build/
src/lynx/static/

# Sphinx documentation
docs/_build/
docs/source/api/generated/
docs/source/.jupyter_cache/
docs/source/**/.ipynb_checkpoints/
docs/source/**/_plots/
*.doctree


# Byte-compiled / optimized / DLL files
__pycache__/
*.py[codz]
Expand Down Expand Up @@ -72,13 +86,6 @@ instance/
# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/
docs/source/api/generated/
docs/source/.jupyter_cache/
docs/source/**/.ipynb_checkpoints/
*.doctree

# PyBuilder
.pybuilder/
target/
Expand Down Expand Up @@ -231,11 +238,6 @@ pnpm-debug.log*
.pnpm-store/
*.tsbuildinfo

# Frontend build output
js/dist/
js/build/
src/lynx/static/

# IDE
.vscode/
.idea/
Expand Down
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ When tests are included, they follow the same user story organization.
- TypeScript 5.9 (frontend), Python 3.11+ (backend) + React 19.2.3, React Flow 11.11.4, anywidget, KaTeX 0.16.27, Pydantic (014-iomarker-latex-rendering)
- JSON diagram files (existing persistence via Pydantic schemas) (014-iomarker-latex-rendering)
- TypeScript 5.9 (frontend), Python 3.11+ (backend) + React 19.2.3, React Flow 11.11.4, anywidget (Jupyter widget framework), Pydantic (schema validation) (015-block-drag-detection)
- Python 3.11+ + Pydantic 2.12+ (existing schema validation), python-control 0.10+ (existing) (017-diagram-label-indexing)

## Key Components

Expand Down Expand Up @@ -605,6 +606,7 @@ blocks/
- `js/src/test/` - Test configuration and setup files

## Recent Changes
- 017-diagram-label-indexing: Added Python 3.11+ + Pydantic 2.12+ (existing schema validation), python-control 0.10+ (existing)
- **015-block-drag-detection**: Intelligent drag detection with 5-pixel movement threshold
- Click-to-select (< 5px movement) vs drag-to-move (≥ 5px movement) behavior
- Uses React Flow 11.11.4's `nodeDragThreshold={5}` prop for automatic click/drag separation
Expand All @@ -628,7 +630,6 @@ blocks/
- 14 backend tests (5 auto-indexing + 6 renumbering + 3 integration), 13 frontend tests (6 parameter editor + 7 block including performance)
- 95% coverage for io_marker.py, renumbering methods fully covered in diagram.py
- TDD approach (RED-GREEN-REFACTOR) throughout implementation with strict test-first discipline
- 013-editable-block-labels: Added TypeScript 5.9 (frontend), Python 3.11+ (backend) + React 19.2.3, React Flow 11.11.4, anywidget (Jupyter widget framework), Pydantic (schema validation)
- Added `diagram.get_ss(from_signal, to_signal)` and `diagram.get_tf(from_signal, to_signal)` API
- 3-tier signal reference system (IOMarker labels → connection labels → block_label.output_port)
- Break-and-inject architecture for subsystem extraction preserving diagram immutability
Expand Down
4 changes: 3 additions & 1 deletion dev/DEV.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ Configuration is in `pyproject.toml` under `[tool.ruff]`.
### Frontend formatting

```bash
cd js && npx prettier --write .
cd js
npx prettier --write .
npm run lint
```

## Type Checking
Expand Down
3 changes: 3 additions & 0 deletions docs/source/_static/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/source/_static/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/source/_static/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
226 changes: 225 additions & 1 deletion docs/source/_static/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,24 @@
--color-admonition-background: rgba(130, 151, 248, 0.15) !important;
}

/* Fix for auto theme mode when system prefers dark */
@media (prefers-color-scheme: dark) {
body:not([data-theme="light"]) {
--color-background-primary: #1f2937 !important;
--color-background-secondary: #111827 !important;
--color-background: #1a1f2e !important;
--color-foreground-primary: #f9fafb !important;
--color-foreground-secondary: #d1d5db !important;

/* Code blocks in dark mode */
--color-code-background: #2d3748 !important;
--color-code-foreground: #f9fafb !important;

/* Admonitions in dark mode */
--color-admonition-background: rgba(130, 151, 248, 0.15) !important;
}
}

/* Font family overrides */
.sidebar-brand-text, h1, h2, h3, h4, h5, h6 {
font-family: 'Roboto Slab', Georgia, serif !important;
Expand Down Expand Up @@ -73,6 +91,17 @@ body {
background-attachment: fixed;
}

/* Auto theme mode - dark grid background */
@media (prefers-color-scheme: dark) {
body:not([data-theme="light"]) {
background-image:
linear-gradient(rgba(129, 140, 248, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(129, 140, 248, 0.05) 1px, transparent 1px);
background-size: 20px 20px;
background-attachment: fixed;
}
}

/* Logo styling in sidebar */
.sidebar-brand-container {
display: flex;
Expand All @@ -86,6 +115,29 @@ body {
margin-right: 16px;
}

/* Remove the "documentation" text */
.sidebar-brand-text::after {
content: "" !important;
}

/* Hide specific titles */
.hidden-title {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
border: 0;
}

/* Reduce spacing for h1 elements that only contain hidden titles */
h1:has(.hidden-title) {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}

/* Terminal-style code blocks with enhanced styling */
.highlight {
position: relative;
Expand All @@ -99,11 +151,12 @@ body {
[data-theme="dark"] .highlight {
border-color: var(--color-border-tech);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
background-color: var(--color-bg-code);
}

/* Terminal header bar - dynamic based on language */
.highlight::before {
content: '▸ code';
/* content: '▸ code'; */
display: block;
padding: 0.5rem 1rem;
background: linear-gradient(180deg, #f9fafb 0%, #f3f4f6 100%);
Expand Down Expand Up @@ -239,6 +292,18 @@ body {
display: none;
}

/* Fix: Ensure code blocks in notebook cells have dark background in dark mode */
[data-theme="dark"] .cell_input .highlight-ipython3 pre,
[data-theme="dark"] .cell_input .highlight pre,
[data-theme="dark"] .cell_input .highlight {
background-color: var(--color-bg-code) !important;
}

[data-theme="dark"] .cell_input .highlight-ipython3,
[data-theme="dark"] .highlight-ipython3 .highlight {
background-color: var(--color-bg-code) !important;
}

/* Cell output styling */
.cell_output {
margin-top: 0.5rem;
Expand Down Expand Up @@ -436,3 +501,162 @@ a.reference.external::after {
border-radius: 6px;
}
}

/* ============================================
Auto Theme Mode Dark Styles
When body[data-theme="auto"] and system prefers dark
============================================ */
@media (prefers-color-scheme: dark) {
/* Code blocks and highlights */
body:not([data-theme="light"]) .highlight {
border-color: var(--color-border-tech);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
background-color: var(--color-bg-code);
}

body:not([data-theme="light"]) .highlight::before {
background: linear-gradient(180deg, #1f2937 0%, #111827 100%);
border-bottom-color: var(--color-border-tech);
color: #9ca3af;
}

body:not([data-theme="light"]) .highlight pre {
background-color: var(--color-bg-code) !important;
}

body:not([data-theme="light"]) pre {
background-color: var(--color-bg-code) !important;
border: 1px solid var(--color-border-tech);
}

/* Syntax highlighting colors */
body:not([data-theme="light"]) .highlight .s1 { color: #fca5a5; }
body:not([data-theme="light"]) .highlight .nn { color: #86efac; }
body:not([data-theme="light"]) .highlight .nb { color: #93c5fd; }
body:not([data-theme="light"]) .highlight .k { color: #a5b4fc; }
body:not([data-theme="light"]) .highlight .n { color: #f9fafb; }
body:not([data-theme="light"]) .highlight .mi { color: #fde047; }
body:not([data-theme="light"]) .highlight .kc { color: #f0abfc; }

/* Function signatures */
body:not([data-theme="light"]) .sig {
background-color: #2d3748 !important;
}

/* Tables */
body:not([data-theme="light"]) table.docutils {
border-color: #374151;
}

body:not([data-theme="light"]) table.docutils thead {
background-color: #2d3748;
}

body:not([data-theme="light"]) table.docutils tbody tr:nth-child(odd) {
background-color: #1f2937;
}

body:not([data-theme="light"]) table.docutils tbody tr:nth-child(even) {
background-color: #2d3748;
}

/* Theme images */
body:not([data-theme="light"]) .only-light {
display: none;
}

body:not([data-theme="light"]) .only-dark {
display: block;
}

/* Notebook cells */
body:not([data-theme="light"]) .cell_input {
border-left-color: var(--color-signal-input);
background-color: rgba(16, 185, 129, 0.05);
}

body:not([data-theme="light"]) .cell_input .highlight-ipython3 pre,
body:not([data-theme="light"]) .cell_input .highlight pre,
body:not([data-theme="light"]) .cell_input .highlight {
background-color: var(--color-bg-code) !important;
}

body:not([data-theme="light"]) .cell_input .highlight-ipython3,
body:not([data-theme="light"]) .highlight-ipython3 .highlight {
background-color: var(--color-bg-code) !important;
}

body:not([data-theme="light"]) .cell_output {
background-color: rgba(245, 158, 11, 0.05);
}

/* Inline code */
body:not([data-theme="light"]) code.literal {
background-color: rgba(129, 140, 248, 0.15);
color: var(--lynx-indigo-bright);
border-color: rgba(129, 140, 248, 0.25);
}

/* Function signatures */
body:not([data-theme="light"]) .sig {
background: linear-gradient(135deg, #1f2937 0%, #111827 100%);
border-color: var(--color-border-tech);
border-left-color: var(--lynx-indigo-bright);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}

/* Admonitions */
body:not([data-theme="light"]) .admonition.note,
body:not([data-theme="light"]) .admonition.seealso {
background-color: rgba(16, 185, 129, 0.1);
}

body:not([data-theme="light"]) .admonition.warning,
body:not([data-theme="light"]) .admonition.attention,
body:not([data-theme="light"]) .admonition.caution {
background-color: rgba(245, 158, 11, 0.1);
}

body:not([data-theme="light"]) .admonition.danger,
body:not([data-theme="light"]) .admonition.error {
background-color: rgba(239, 68, 68, 0.1);
}

body:not([data-theme="light"]) .admonition.tip,
body:not([data-theme="light"]) .admonition.hint,
body:not([data-theme="light"]) .admonition.important {
background-color: rgba(129, 140, 248, 0.1);
}

/* Cards */
body:not([data-theme="light"]) .sd-card:hover {
box-shadow: 0 4px 16px rgba(130, 151, 248, 0.2);
}

/* Scrollbars */
body:not([data-theme="light"]) ::-webkit-scrollbar {
width: 10px;
height: 10px;
}

body:not([data-theme="light"]) ::-webkit-scrollbar-track {
background: #1f2937;
}

body:not([data-theme="light"]) ::-webkit-scrollbar-thumb {
background: #374151;
border-radius: 5px;
}

body:not([data-theme="light"]) ::-webkit-scrollbar-thumb:hover {
background: #4b5563;
}

/* Hero video */
body:not([data-theme="light"]) .hero-video {
border-color: var(--color-border-tech);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
background-color: #1a1f2e;
}
}

3 changes: 3 additions & 0 deletions docs/source/_static/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/source/_static/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/_static/favicon.ico
Binary file not shown.
3 changes: 0 additions & 3 deletions docs/source/_static/favicon.svg

This file was deleted.

Loading