Metadata-Version: 2.4
Name: ggblab
Version: 0.8.7
Summary: A JupyterLab extension.
Project-URL: Homepage, https://github.com/moyhig-ecs/ggblab#readme
Project-URL: Bug Tracker, https://github.com/moyhig-ecs/ggblab/issues
Project-URL: Repository, https://github.com/moyhig-ecs/ggblab
Author-email: Manabu Higashida <manabu@higashida.net>
License: BSD 3-Clause License
        
        Copyright (c) 2025, ggblab
        All rights reserved.
        
        Redistribution and use in source and binary forms, with or without
        modification, are permitted provided that the following conditions are met:
        
        1. Redistributions of source code must retain the above copyright notice, this
           list of conditions and the following disclaimer.
        
        2. Redistributions in binary form must reproduce the above copyright notice,
           this list of conditions and the following disclaimer in the documentation
           and/or other materials provided with the distribution.
        
        3. Neither the name of the copyright holder nor the names of its
           contributors may be used to endorse or promote products derived from
           this software without specific prior written permission.
        
        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
        AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
        FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
        CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
        OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
License-File: LICENSE
Keywords: jupyter,jupyterlab,jupyterlab-extension
Classifier: Framework :: Jupyter
Classifier: Framework :: Jupyter :: JupyterLab
Classifier: Framework :: Jupyter :: JupyterLab :: 4
Classifier: Framework :: Jupyter :: JupyterLab :: Extensions
Classifier: Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.10
Requires-Dist: aiofiles
Requires-Dist: ipylab
Requires-Dist: networkx
Requires-Dist: polars
Requires-Dist: websockets
Requires-Dist: xmlschema
Requires-Dist: xmltodict
Description-Content-Type: text/markdown

# ggblab

ggblab is a JupyterLab extension that opens a GeoGebra applet inside JupyterLab and lets you drive it from a Python kernel. The panel can be launched from the Command Palette or Launcher for default settings, but to enable kernel↔widget communication reliably ggblab launches the widget programmatically from a notebook (via ipylab) so communication settings are passed before initialization. You then call GeoGebra commands/functions asynchronously from Python via IPython Comm plus an optional Unix-socket/TCP WebSocket bridge.

### Features

- Programmatic launch via `GeoGebra().init()` (recommended), which uses ipylab to pass communication settings before widget initialization (Command ID: `ggblab:create`, label: "React Widget"). Command Palette/Launcher work only with fixed arguments and are suitable for default settings.
- Call GeoGebra commands (`command`) and API functions (`function`) from Python through the `GeoGebra` helper
- Combined IPython Comm + Unix domain socket (POSIX) / TCP WebSocket channel for fast data exchange
- Frontend watches add/remove/rename/clear events and dialog messages and forwards them to the kernel
- Settings schema is wired up (no user options yet) for future configuration

### Requirements

- JupyterLab >= 4.0
- Python >= 3.10
- Browser access to https://cdn.geogebra.org/apps/deployggb.js
- For development: Node.js and `jlpm`

### Installation

```bash
pip install ggblab
jupyter labextension list | grep ggblab
```

Uninstall:

```bash
pip uninstall ggblab
```

### Quick Start (UI)

1. Open JupyterLab
2. Run "React Widget" from the Command Palette (category "Tutorial") or click the Launcher tile under "example"
3. A GeoGebra panel opens in the main area; layout restoration and launcher integration are enabled

### Quick Start (Notebook/Python)

```python
from ggblab.ggbapplet import GeoGebra

ggb = GeoGebra()
await ggb.init()                 # init IPython Comm/socket and open the GeoGebra panel

await ggb.command("A=(0,0)")    # create a point
value = await ggb.function("getValue", ["A"])  # call GeoGebra API
print(value)
```

`init()` fetches the current kernel ID, starts the IPython Comm/WebSocket server, and triggers the frontend command `ggblab:create` to open the panel. `command` sends GeoGebra commands; `function` calls GeoGebra API names (single name or list) and returns the result asynchronously.

## Documentation

ggblab's design philosophy and implementation details are documented across several focused documents:

Note: Documentation has moved under docs/. Start at [docs/index.md](docs/index.md). Legacy copies are retained in docs_archive/ (git-ignored) for reference.

### Core Documentation

- **[philosophy.md](docs/philosophy.md)** - Design principles, scope boundaries, and educational vision
  - Communication architecture maturity and stability assessment
  - GeoGebra + Python complementarity framework
  - Geometric Scene evolution inspired by Wolfram's GeometricScene paradigm
  - Manim video export as the ultimate pedagogical goal
  - Prioritized technical roadmap (Tiers 1-5) focused on learning value
  - Success criteria for each version milestone (v0.8 - v1.5+)

- **[scoping.md](docs/scoping.md)** - **Core Educational Mission**: Variable scoping via geometric construction
  - **The foundational insight**: Geometric dependencies (points → lines → circles) are isomorphic to programming scopes (global → function → nested)
  - How GeoGebra's construction protocol naturally forms a scope tree
  - Computational thinking pedagogy through geometric decomposition, pattern recognition, abstraction, and algorithm design
  - Concrete lesson plans for teaching Python scoping using geometric constructions
  - Classroom integration roadmap with assessment rubrics
  - Cognitive science rationale: Dual Coding Theory, Transfer of Learning, Constructivism

- **[architecture.md](docs/architecture.md)** - Technical implementation details
  - Dual-channel communication design (IPython Comm + Unix socket/TCP WebSocket)
  - Message flow patterns and error handling strategies
  - Dependency parser architecture with performance analysis
  - Critical limitations of `parse_subgraph()` and recommended v1.0 algorithm replacement
  - Resource cleanup and security considerations
  - Testing strategies and development workflow

- **[TODO.md](TODO.md)** - Actionable development roadmap
  - 7 priority areas: Parser, Type Safety, Error Handling, CI/CD, Documentation, Configuration, Monitoring
  - Version targets (v0.7.3 - v1.0+) with concrete implementation tasks
  - Blocking issues and dependency tracking
  - Quick-fix vs. long-term architectural improvements

### Advanced Integration

- **[sympy_integration.md](docs/sympy_integration.md)** - Symbolic computation and code generation
  - Bidirectional conversion: GeoGebra constructions ↔ SymPy Geometry objects
  - Symbolic verification of geometric properties (collinearity, concyclicity, perpendicularity)
  - Automatic Python code generation from constructions (reproducibility + version control)
  - Advanced solvers: locus equations, envelope curves, constraint satisfaction
  - Manim export pipeline: SymPy geometry → manim animation code
  - Implementation roadmap (v1.1 - v1.5) with educational success criteria

### Quick Reference

| Document | Primary Audience | Key Insight |
|----------|-----------------|-------------|
| **SCOPING.md** | Educators, Students | Geometric construction teaches programming scoping |
| **PHILOSOPHY.md** | Contributors, Researchers | ggblab = GeoGebra → Timeline → Manim → Video pipeline |
| **SYMPY_INTEGRATION.md** | Math/CS Instructors | Symbolic proof + code generation + manim export |
| **ARCHITECTURE.md** | Developers | Dual-channel communication; parser needs v1.0 redesign |
| **TODO.md** | Contributors | Concrete next steps prioritized by learning value |

### Examples

- Sample notebook: [examples/example.ipynb](examples/example.ipynb)
- Demo video:

<video src="https://github.com/user/repo/assets/example.mov" controls width="100%">
  <source src="examples/example.mov" type="video/quicktime">
  Your browser does not support the video tag. Please <a href="examples/example.mov">download the video</a> directly.
</video>

Run steps:

```python
%load_ext autoreload
%autoreload 2

from ggblab import GeoGebra
import io

ggb = await GeoGebra().init()  # open GeoGebra widget on the left

c = ggb.construction.load('/path/to/your.ggb')  # supports .ggb, zip, JSON, XML
o = c.ggb_schema.decode(io.StringIO(c.geogebra_xml))  # geogebra_xml is auto-stripped to construction
o
```

Note: Supports `.ggb` (base64-encoded zip), plain zip, JSON, and XML formats. The `geogebra_xml` is automatically narrowed to the `construction` element and scientific notation is normalized. Schema/decoding APIs may evolve.

### Saving construction

Save the current construction (archive when Base64 is set, otherwise plain XML):

```python
from ggblab import GeoGebra

ggb = await GeoGebra().init()
c = ggb.construction.load('/path/to/your.ggb')

# Save to XML (when no Base64 is set)
c.save('/tmp/construction.xml')

# Save to a .ggb file name; content depends on state:
# - if Base64 is set -> decoded archive (.ggb zip)
# - else -> plain XML bytes (extension does not enforce format)
c.save('/tmp/construction.ggb')
```

#### Saving behavior and defaults

- `c.save()` with no arguments writes to the next available filename derived from the originally loaded `source_file` (e.g., `name_1.ggb`, `name_2.ggb`, ...). Use `c.save(overwrite=True)` to overwrite the original `source_file`.
- If `construction.base64_buffer` is set (e.g., from `getBase64()` or `load()`), `save()` writes the decoded archive; otherwise it writes the in-memory `geogebra_xml` as plain XML.
- Target file extension does not enforce format: if Base64 is absent, saving to a `.ggb` path will still write plain XML bytes.
- Note: `getBase64()` from the applet may not include non-XML artifacts present in the original `.ggb` archive (e.g., thumbnails or other resources). Saving after API-driven changes can therefore produce a leaner archive.

### Use Cases (from examples/eg3_applet.ipynb)

#### 1) Algebraic commands and API functions

```python
# Algebraic command
r = await ggb.command("O = (0, 0)")

# API functions
r = await ggb.function("getAllObjectNames")
r = await ggb.function("newConstruction")
```

#### 2) Load .ggb and draw via Base64

```python
# Load a .ggb (base64-encoded zip)
c = ggb.construction.load('path/to/file.ggb')

# Render in applet
await ggb.function("setBase64", [ggb.construction.base64_buffer.decode('utf-8')])
```

#### 3) Layer visibility control

```python
from itertools import zip_longest

layers = range(10)
await ggb.function("setLayerVisible", list(zip_longest(list(layers), [], fillvalue=False)))
layers = [9, 0]
await ggb.function("setLayerVisible", list(zip_longest(list(layers), [], fillvalue=True)))
```

#### 4) XML attribute edit roundtrip

```python
# Pull XML for object 'A'
r = await ggb.function("getXML", ['A'])

# Decode to schema dict, modify, and encode back
o2 = c.ggb_schema.decode(r)
o2['show'][0]['@object'] = False
x = xmlschema.etree_tostring(c.ggb_schema.encode(o2, 'element'))

# Apply to applet
await ggb.function("evalXML", [x])
```

#### 5) Roundtrip save from applet state

```python
# Fetch current applet state as base64 and save
r = await ggb.function("getBase64")
ggb.construction.base64_buffer = r.encode('ascii')
c.save()              # next available filename based on source_file
# c.save(overwrite=True)  # to overwrite the original
```

### Object Dependency Analysis (Parser)

ggblab includes a **dependency parser** (`ggblab.parser.ggb_parser`) that analyzes object relationships in GeoGebra constructions using **NetworkX graphs**. This enables:

- **Dependency tracking**: Build a directed graph of which objects depend on which others
- **Root/leaf identification**: Find independent starting objects and final dependent objects
- **Subgraph analysis**: Identify minimal construction sequences needed to derive specific objects

#### Basic Usage

```python
from ggblab import GeoGebra
from ggblab.parser import ggb_parser
import networkx as nx

ggb = GeoGebra()
await ggb.init()

# Fetch construction protocol from applet
construction = {}
for obj_name in await ggb.function("getAllObjectNames"):
    obj_info = await ggb.function(
        ["getObjectType", "getCommandString", "getValueString", "getCaption", "getLayer"],
        [obj_name]
    )
    construction[obj_name] = obj_info

# Parse into Polars DataFrame
parser = ggb_parser()
parser.initialize_dataframe(df=pl.DataFrame(construction, strict=False))
parser.parse()  # Build dependency graph

# Access the NetworkX DiGraph
G = parser.G
print(f"Root objects: {parser.roots}")      # Objects with no dependencies
print(f"Leaf objects: {parser.leaves}")      # Objects that nothing depends on

# Traverse dependencies
for obj in parser.roots:
    descendants = nx.descendants(G, obj)  # All objects that depend on this one
    print(f"{obj} -> {descendants}")
```

#### Advanced: Subgraph Extraction

Extract minimal construction sequences needed for specific output objects:

```python
# Analyze subgraph for focused construction steps
parser.parse_subgraph()  # Builds G2 with simplified dependencies
G2 = parser.G2

# Reconstruct only necessary steps
nx.write_network_text(G2)  # View simplified dependency tree
```

#### Parser Components

- **`df`**: Polars DataFrame with columns `Type`, `Command`, `Value`, `Caption`, `Layer` (transposed from construction protocol)
- **`G` (NetworkX DiGraph)**: Full dependency graph; edges point from dependencies to dependents
- **`G2` (NetworkX DiGraph)**: Simplified subgraph with redundant dependencies removed
- **`ft` (dict)**: Tokenized command strings; maps object name → list of tokens (parsed by `tokenize_with_commas()`)
- **`roots` (list)**: Objects with `in_degree == 0` (no incoming dependencies)
- **`leaves` (list)**: Objects with `out_degree == 0` (nothing depends on them)

#### Example Notebook

See [examples/eg4_parse.ipynb](examples/eg4_parse.ipynb) for a complete example of loading a `.ggb`, building dependency graphs, and analyzing construction structure.

### Architecture

- **Frontend** ([src/index.ts](src/index.ts), [src/widget.tsx](src/widget.tsx)): Registers the plugin `ggblab:plugin` and command `ggblab:create`. Creates a `GeoGebraWidget` ReactWidget that loads GeoGebra from the CDN, opens an IPython Comm target (default `test3`), executes commands/functions, and mirrors add/remove/rename/clear events plus dialog notices back to the kernel. Results can also be forwarded over the external socket when provided.
- **Backend** ([ggblab/ggbapplet.py](ggblab/ggbapplet.py), [ggblab/comm.py](ggblab/comm.py), [ggblab/construction.py](ggblab/construction.py), [ggblab/parser.py](ggblab/parser.py)): Initializes a singleton `GeoGebra`, spins up a Unix-socket/TCP WebSocket server, registers the IPython Comm target, and drives the frontend command via ipylab. `ggb_comm.send_recv` waits for responses; `ggb_construction` loads multiple file formats (`.ggb`, zip, JSON, XML) and provides `geogebra_xml` + `ggb_schema` for converting construction XML to schema objects. `ggb_parser` analyzes object dependencies using NetworkX directed graphs.
- **Styles** ([style/index.css](style/index.css), [style/base.css](style/base.css)): Ensure the embedded applet fills the available area.

#### Communication Architecture

**Dual-channel design**: ggblab uses two communication channels between the frontend and backend:

1. **Primary channel (IPython Comm over WebSocket)**:
   - Handles command/function calls and event notifications
   - Managed by Jupyter/JupyterHub infrastructure with reverse proxy support
   - Connection health guaranteed by Jupyter/JupyterHub
   - **Limitation**: IPython Comm cannot receive messages while a notebook cell is executing

2. **Out-of-band channel (Unix Domain Socket on POSIX / TCP WebSocket on Windows)**:
   - Addresses the Comm limitation by enabling message reception during cell execution
   - Allows GeoGebra applet responses to be received even when Python is busy executing code
   - Connection is opened/closed per transaction (no persistent connection)
   - No auto-reconnection needed due to transient nature

This dual-channel approach ensures that interactive operations (e.g., retrieving object values, updating constructions) remain responsive even during long-running cell execution.

See [architecture.md](docs/architecture.md) for detailed design rationale and implementation notes.

#### Error Handling and Limitations

**Primary channel (IPython Comm)**: Error handling is managed automatically by Jupyter/JupyterHub infrastructure. Connection failures are detected and handled transparently; kernel status is visible in the JupyterLab UI.

**Out-of-band channel**: The secondary channel has a **3-second timeout** for receiving responses. If no response arrives within this window, a `TimeoutError` is raised in Python:

```python
try:
    result = await ggb.function("getValue", ["a"])
except TimeoutError:
    print("GeoGebra did not respond within 3 seconds")
```

**GeoGebra API constraint**: The GeoGebra API does **not** provide explicit error response codes. Instead, errors are communicated through **dialog popups** displayed in the browser. The frontend monitors these dialog events and forwards error information via the primary Comm channel. For errors that do not trigger dialogs (e.g., malformed responses), the timeout is the primary error signal.

See [architecture.md § Error Handling](docs/architecture.md#error-handling) for details on error detection and recovery strategies.

### Settings

The current settings schema ([schema/plugin.json](schema/plugin.json)) exposes no user options yet but is ready for future configuration.

### Development Workflow

```bash
pip install -e ".[dev]"
jupyter labextension develop . --overwrite
jlpm build           # or `jlpm watch` during development
jupyter lab          # run in another terminal
```

To remove the dev link, uninstall and delete the `ggblab` symlink listed by `jupyter labextension list`.

### Testing

- Frontend: `jlpm install && jlpm test`
- Integration (Playwright/Galata): see [ui-tests/README.md](ui-tests/README.md); build with `jlpm build:prod`, then `cd ui-tests && jlpm install && jlpm playwright test`

### Release

See [RELEASE.md](RELEASE.md) for publishing to PyPI/NPM or using Jupyter Releaser; bump versions with `hatch version`.

### Known Issues and Gaps

#### Frontend Limitations

- **No explicit error handling UI**: Communication failures between frontend and backend are logged to console but not displayed to users. Currently relies on browser console for debugging.
- **Limited event notification**: Only monitors basic GeoGebra events (add/remove/rename/clear objects, dialogs). Advanced events like slider changes, conditional visibility toggles, or script execution results are not automatically propagated.
- **Hardcoded Comm target**: The Comm target name is hardcoded as `'test3'` with no option for customization without code changes.
- **TypeScript strict checks disabled**: Some type assertions use `any` type, reducing type safety. Widget props lack full interface documentation.
- **No input validation**: Commands and function arguments are not validated before sending to GeoGebra; invalid requests may cause silent failures.

#### Backend Limitations

- **Singleton pattern constraint**: Only one active GeoGebra instance per kernel session. Attempting to create multiple instances will reuse the same connection.
- **Out-of-band communication timeout**: The out-of-band socket channel has a 3-second timeout. If the frontend does not respond within this window, the backend raises a timeout exception.
- **Limited error handling on out-of-band channel**: GeoGebra API does not provide explicit error responses, so errors are communicated indirectly:
  - GeoGebra displays error dialogs (native popups) when operations fail (e.g., invalid syntax in algebraic commands)
  - The frontend monitors dialog events and forwards error messages via the primary Comm channel
  - Errors without a dialog (e.g., malformed JSON responses) result in timeout exceptions or silent failures
- **Parser subgraph extraction (`parse_subgraph()`) performance issues**:
  - **Combinatorial explosion**: Generates $2^n$ path combinations where $n$ = number of root objects. Performance degrades rapidly with 15+ independent roots.
  - **Infinite loop risk**: May hang indefinitely under certain graph topologies.
  - **Limited N-ary dependency support**: Only handles 1-ary and 2-ary dependencies; 3+ objects jointly creating an output are ignored.
  - **Redundant computation**: Neighbor lookups are recalculated unnecessarily in loops.
   - See [architecture.md § Dependency Parser Architecture](docs/architecture.md#dependency-parser-architecture) for detailed analysis and planned improvements.

#### General Limitations

- **No unit tests**: Backend Python code lacks comprehensive unit tests.
- **Incomplete integration tests**: No Playwright tests yet for critical workflows (command execution, file loading, event handling).
- **No CI/CD pipeline**: No automated testing on pull requests or releases.
- **Minimal documentation**: No dedicated developer guide beyond code comments; architecture rationale is not documented.

### Project Assessment (Objective)

- **Maturity**: Early-stage (0.x). Core functionality works for driving GeoGebra via dual channels, but lacks automated verification and release safeguards.
- **Strengths**: Clear architecture docs; dual-channel communication to mitigate Comm blocking; supports multiple file formats; dependency parser groundwork.
- **Key Risks**: No CI, low test coverage (unit/integration absent); parser `parse_subgraph()` has performance/loop risks on large graphs; hardcoded Comm target; minimal UX for error surfacing.
- **Maintainability**: TypeScript not strict; some `any` and limited input validation; parser algorithm needs replacement for scale.
- **Operational Gaps**: No monitoring/telemetry; no retry/backoff around sockets; release process manual.

### Future Enhancements and Roadmap

#### Short Term (v0.8.x)

1. **Error Handling & User Feedback**
   - Add user-facing error notifications for Comm/WebSocket failures
   - Improve out-of-band error reporting: detect timeout conditions and propagate as Python exceptions with context
   - Support for custom timeout configuration in `GeoGebra()` initialization
   - Enhanced error message recovery from GeoGebra dialog content
   - Provide more descriptive error messages in the UI when operations fail

2. **Parser Optimization** (`v0.7.3`)
   - Remove debug output; add optional logging via `logging` module
   - Add early termination check to detect infinite loops in `parse_subgraph()`
   - Cache neighbor computation to reduce redundant graph traversals
   - Extend N-ary dependency support (currently limited to 1-2 parents; should support 3+)

3. **Event System Expansion**
   - Subscribe to additional GeoGebra events (slider value changes, object property changes, script execution)
   - Expose event system to Python API via `ggb.on_event()` pattern
   - Log all events with timestamps for debugging

4. **Configuration & Customization**
   - Add settings UI to choose Comm target name and socket configuration
   - Allow custom GeoGebra CDN URL (for offline or private CDN scenarios)
   - Implement widget position/size preferences (split-right, split-left, tab, etc.)

#### Medium Term (v1.0)

1. **Type Safety & Code Quality**
   - Enable TypeScript strict mode and eliminate `any` types
   - Add JSDoc for all public TypeScript/Python APIs
   - Increase test coverage to >80% for both frontend and backend
   - Add comprehensive unit tests for parser, especially for edge cases and large graphs

2. **Parser Algorithm Replacement**
   - Replace `parse_subgraph()` with topological sort + reachability pruning approach
   - Reduce time complexity from $O(2^n)$ to $O(n(n+m))$
   - Support arbitrary N-ary dependencies (not limited to 2 parents)
   - Eliminate infinite loop risk through deterministic algorithm
   - See [ARCHITECTURE.md § Dependency Parser Architecture](ARCHITECTURE.md#dependency-parser-architecture) for detailed design

3. **Advanced Features**
   - **Multi-panel support**: Allow multiple GeoGebra instances in different notebook cells
   - **State persistence**: Save/restore GeoGebra construction state to notebook or file
   - **Real-time collaboration**: Support multiple users viewing/editing the same construction
   - **Animation API**: Programmatic animation of objects with timeline control
   - **Custom tool definitions**: Allow users to define and persist custom GeoGebra tools

4. **Integration Improvements**
   - **Jupyter Widgets (ipywidgets) support**: Make GeoGebra embeddable in `ipywidgets` environments
   - **Matplotlib/Plotly integration**: Export construction data to visualization libraries
   - **NumPy/Pandas integration**: Bidirectional data sync with DataFrames

#### Long Term (v1.5+)

1. **Performance & Scalability**
   - WebSocket batching for high-frequency updates (e.g., animations)
   - Caching layer for repeated function calls
   - Support for serverless/container environments without persistent sockets
   - Memoization of subgraph extraction results

2. **ML/Data Science Features**
   - Built-in geometry solvers with numerical optimization (scipy integration)
   - Constraint solving interface
   - Interactive visualization of mathematical models

3. **Parser Enhancements**
   - Weighted edges representing construction order preference
   - Interactive subgraph selection UI
   - Integration with constraint solving for optimal construction paths
   - Interactive visualization of mathematical models

3. **Ecosystem & Standards**
   - JupyterHub compatibility testing and official support
   - Jupyter Notebook (classic) extension variant
   - Conda-forge packaging
   - Official plugin for popular JupyterLab distributions (JupyterHub, Google Colab, etc.)

### Contributing

Contributions are welcome! Please:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/xyz`)
3. Commit with clear messages
4. Run tests and linting: `jlpm lint && jlpm test`
5. Submit a pull request

For major changes, please open an issue first to discuss.

### License

BSD-3-Clause
