foxsnakecode 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. foxsnakecode-1.0.0/.gitignore +11 -0
  2. foxsnakecode-1.0.0/.releaserc.json +12 -0
  3. foxsnakecode-1.0.0/.yarnrc.yml +2 -0
  4. foxsnakecode-1.0.0/CHANGELOG.md +6 -0
  5. foxsnakecode-1.0.0/LICENSE +21 -0
  6. foxsnakecode-1.0.0/PKG-INFO +152 -0
  7. foxsnakecode-1.0.0/README.md +134 -0
  8. foxsnakecode-1.0.0/demo/environment.yml +8 -0
  9. foxsnakecode-1.0.0/demo/jupyter-lite.json +16 -0
  10. foxsnakecode-1.0.0/demo/jupyter_lite_config.json +12 -0
  11. foxsnakecode-1.0.0/docs/grep-fox.png +0 -0
  12. foxsnakecode-1.0.0/docs/sudo-snake.svg +41 -0
  13. foxsnakecode-1.0.0/foxsnakecode/__init__.py +8 -0
  14. foxsnakecode-1.0.0/foxsnakecode/_version.py +4 -0
  15. foxsnakecode-1.0.0/foxsnakecode/engine.py +339 -0
  16. foxsnakecode-1.0.0/foxsnakecode/labextension/package.json +82 -0
  17. foxsnakecode-1.0.0/foxsnakecode/labextension/static/232.95f9b339dd39bfc1.js +1317 -0
  18. foxsnakecode-1.0.0/foxsnakecode/labextension/static/727.cb038f1218fc701b.js +243 -0
  19. foxsnakecode-1.0.0/foxsnakecode/labextension/static/remoteEntry.e67f3120757332a1.js +1 -0
  20. foxsnakecode-1.0.0/foxsnakecode/labextension/static/style.js +4 -0
  21. foxsnakecode-1.0.0/foxsnakecode/labextension/static/third-party-licenses.json +16 -0
  22. foxsnakecode-1.0.0/foxsnakecode/missions.json +1547 -0
  23. foxsnakecode-1.0.0/install.json +5 -0
  24. foxsnakecode-1.0.0/package.json +77 -0
  25. foxsnakecode-1.0.0/pyproject.toml +60 -0
  26. foxsnakecode-1.0.0/script/build-demo.mjs +29 -0
  27. foxsnakecode-1.0.0/script/update-demo.mjs +98 -0
  28. foxsnakecode-1.0.0/src/art.ts +399 -0
  29. foxsnakecode-1.0.0/src/audio.ts +283 -0
  30. foxsnakecode-1.0.0/src/engine.ts +65 -0
  31. foxsnakecode-1.0.0/src/format.ts +333 -0
  32. foxsnakecode-1.0.0/src/hint.ts +103 -0
  33. foxsnakecode-1.0.0/src/index.ts +150 -0
  34. foxsnakecode-1.0.0/src/map.ts +107 -0
  35. foxsnakecode-1.0.0/src/panel.ts +1013 -0
  36. foxsnakecode-1.0.0/src/runner.ts +188 -0
  37. foxsnakecode-1.0.0/src/stage.ts +360 -0
  38. foxsnakecode-1.0.0/style/base.css +1316 -0
  39. foxsnakecode-1.0.0/style/index.css +1 -0
  40. foxsnakecode-1.0.0/style/index.js +1 -0
  41. foxsnakecode-1.0.0/tsconfig.json +25 -0
  42. foxsnakecode-1.0.0/yarn.lock +9224 -0
@@ -0,0 +1,11 @@
1
+ *.tsbuildinfo
2
+ .ipynb_checkpoints/
3
+ .yarn/
4
+ __pycache__/
5
+ demo/.jupyterlite.doit.db
6
+ demo/_output/
7
+ dist/
8
+ foxsnakecode/_version.py
9
+ foxsnakecode/labextension/
10
+ lib/
11
+ node_modules/
@@ -0,0 +1,12 @@
1
+ {
2
+ "branches": ["main"],
3
+ "plugins": [
4
+ "@semantic-release/commit-analyzer",
5
+ "@semantic-release/release-notes-generator",
6
+ ["@semantic-release/changelog", { "changelogFile": "CHANGELOG.md" }],
7
+ ["@semantic-release/npm", { "npmPublish": false }],
8
+ ["@semantic-release/exec", { "prepareCmd": "jlpm build:prod && python -m build --no-isolation" }],
9
+ ["@semantic-release/git", { "assets": ["CHANGELOG.md", "package.json"], "message": "chore(release): ${nextRelease.version} [skip ci]" }],
10
+ "@semantic-release/github"
11
+ ]
12
+ }
@@ -0,0 +1,2 @@
1
+ nodeLinker: node-modules
2
+ enableTelemetry: false
@@ -0,0 +1,6 @@
1
+ # 1.0.0 (2026-11-08)
2
+
3
+
4
+ ### Features
5
+
6
+ * release ([36b9ebd](https://github.com/trungleduc/FoxSnakeCode/commit/36b9ebdf258e202f83d8b24419bea473c133196b))
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Trung Le Duc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,152 @@
1
+ Metadata-Version: 2.5
2
+ Name: foxsnakecode
3
+ Version: 1.0.0
4
+ Summary: A coding puzzle game for JupyterLab and JupyterLite
5
+ Author-email: Trung Le <trung.le@quantstack.net>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Keywords: jupyter,jupyterlab,jupyterlab-extension
9
+ Classifier: Framework :: Jupyter
10
+ Classifier: Framework :: Jupyter :: JupyterLab
11
+ Classifier: Framework :: Jupyter :: JupyterLab :: 4
12
+ Classifier: Framework :: Jupyter :: JupyterLab :: Extensions
13
+ Classifier: Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt
14
+ Classifier: Programming Language :: Python :: 3
15
+ Requires-Python: >=3.10
16
+ Requires-Dist: jupyter-ai-lite<0.22,>=0.21
17
+ Description-Content-Type: text/markdown
18
+
19
+ <div align="center">
20
+ <img src="docs/grep-fox.png" width="140" alt="Grep Fox">
21
+ <img src="docs/sudo-snake.svg" width="140" alt="Sudo Snake">
22
+
23
+ <h1>FoxSnakeCode</h1>
24
+ <p><strong>Tactical Coding Action</strong></p>
25
+ <p>Coding missions, challenges, stealth debugging, boss levels...</p>
26
+ <p><em>Write Python. Slip past the searchlights. Steal the data.</em></p>
27
+ <p><a href="https://trungleduc.github.io/FoxSnakeCode/lab/"><strong>Try it in your browser</strong></a></p>
28
+ </div>
29
+
30
+ ## Meet the team
31
+
32
+ | | Codename | Role | |
33
+ | --- | --- | --- | --- |
34
+ | 🦊 | **Grep Fox** | Field agent | Sniffs out any word, in any file, in a flash. Your code tells Grep Fox where to go. |
35
+ | 🐍 | **Sudo Snake** | HQ | Sneaks past bugs and runs every command with superpowers. Briefs you on every mission. |
36
+
37
+ ## How it plays
38
+
39
+ 1. Click FoxSnakeCode in the launcher to start a new game, or double-click a saved `.fsc` file.
40
+ 2. Pick the next open level on the map. Solving a level unlocks the one after it, and every 10th level is a boss.
41
+ 3. Read your briefing from Sudo Snake.
42
+ 4. Write Python, then press Run.
43
+ 5. Watch Grep Fox dodge searchlights, lasers and decoys to grab every data chip.
44
+
45
+ FoxSnakeCode runs in JupyterLab and JupyterLite. Your code runs on a Python kernel, and xeus-python is preferred. The `foxsnakecode` package must be installed in the same environment as the kernel.
46
+
47
+ ## Hints from Sudo Snake
48
+
49
+ Press **Ask for a hint** during a mission to chat with Sudo Snake. Hints use [jupyter-ai-lite](https://github.com/jupyterlite/ai), so players connect their own AI provider or sign in with OpenRouter from **Set up AI**. By default the key is kept in memory and cleared when the page reloads. Never put your own API key in a deployed site, because anyone can read it.
50
+
51
+ Sudo Snake only sees the current level, the player's code and their last result, and has no tools. Its instructions keep it on the game and away from full solutions, but they run in the player's browser and are not a guarantee. The demo site turns off the general AI chat and code completion.
52
+
53
+ ## Install for development
54
+
55
+ ```bash
56
+ micromamba create -n cgs -c conda-forge python=3.12 'jupyterlab=4.*' 'nodejs=22' xeus-python jupyterlite-core jupyterlite-xeus pip
57
+ micromamba activate cgs
58
+ pip install -e .
59
+ jupyter labextension develop . --overwrite
60
+ jlpm install
61
+ jlpm build
62
+ jupyter lab
63
+ ```
64
+
65
+ Then click FoxSnakeCode in the launcher.
66
+
67
+ The game logic is in `foxsnakecode/engine.py` and the levels are in `foxsnakecode/missions.json`. After editing the engine, press Stop or restart the kernel to load the new code. After editing the levels, close and reopen the game.
68
+
69
+ ## JupyterLite demo site
70
+
71
+ The `demo` folder holds a JupyterLite site with xeus-python running in the browser. Build the site with the extension installed:
72
+
73
+ ```bash
74
+ pip install build hatchling hatch-nodejs-version hatch-jupyter-builder
75
+ jlpm build:demo
76
+ ```
77
+
78
+ This builds the `foxsnakecode` wheel and installs it into the site's kernel. The site is written to `demo/_output`, which you can host on any static web server.
79
+
80
+ After changing the extension, the Python package or the missions, `jlpm update:demo` copies them into an existing `demo/_output` without a full rebuild.
81
+
82
+ A local demo build keeps files in memory only, so nothing is saved in the browser and reloading the page loses any game you started.
83
+
84
+ The site deployed to GitHub Pages saves games in the player's browser instead.
85
+
86
+ Stop restarts the kernel, so the next Run can take a few seconds in JupyterLite.
87
+
88
+ ## Commands players can use
89
+
90
+ | Command | What it does |
91
+ | --- | --- |
92
+ | `step(distance)` | Walk forward. A negative number walks backward. |
93
+ | `turn(degrees)` | Turn right. A negative number turns left. |
94
+ | `turn_to(target)` | Face a chip, a guard or an `(x, y)` position. |
95
+ | `distance_to(target)` | Get the distance to a chip, a guard or an `(x, y)` position. |
96
+ | `wait(seconds)` | Stay still for a number of seconds. |
97
+ | `chips` | The list of chips. Each has `x`, `y`, `trapped` and `collected`. |
98
+ | `guards` | The list of guards. Each has `x`, `y` and `angle`, and they update as time passes. |
99
+
100
+ A level is solved when every chip that isn't trapped has been collected. Searchlights, lasers, trapped chips and being spotted by a guard end the attempt, while crates and walls just block the way.
101
+
102
+ ## Adding levels
103
+
104
+ Levels are in `foxsnakecode/missions.json`, and their order in the list is their order on the map. The world is 800 by 500 steps, with `x` increasing to the right and `y` increasing downward. An `angle` of 0 faces right.
105
+
106
+ ```json
107
+ {
108
+ "title": "FoxSnakeCode",
109
+ "levels": [
110
+ {
111
+ "id": "first-steps",
112
+ "title": "First Steps",
113
+ "instructions": "Reach the chip with `step`.",
114
+ "starterCode": "step(100)\n",
115
+ "scene": {
116
+ "start": { "x": 100, "y": 250, "angle": 0 },
117
+ "chips": [{ "x": 400, "y": 250 }, { "x": 600, "y": 250, "trapped": true }],
118
+ "obstacles": [{ "x": 300, "y": 50, "w": 100, "h": 100 }],
119
+ "hazards": [
120
+ { "x": 600, "y": 100, "r": 50 },
121
+ { "x": 200, "y": 400, "w": 300, "h": 6 }
122
+ ],
123
+ "guards": [
124
+ { "route": [{ "x": 200, "y": 300 }, { "x": 600, "y": 300 }], "speed": 80 }
125
+ ]
126
+ }
127
+ }
128
+ ]
129
+ }
130
+ ```
131
+
132
+ Each level needs a unique `id`. Saved games refer to levels by `id`, so never change one after release; new levels can go anywhere in the list without breaking saves. Add `"boss": true` to mark a boss level.
133
+
134
+ In `hazards`, an item with `r` is a searchlight and an item with `w` and `h` is a laser. Text between backticks in `instructions` is shown as code.
135
+
136
+ In `guards`, each guard walks its `route` at `speed` steps per second, then returns to the first point and starts again. Grep Fox is spotted inside a guard's vision cone or by touching the guard, and crates block the cone. Put guard routes where they don't pass through crates.
137
+
138
+ ## The `.fsc` file
139
+
140
+ A `.fsc` file holds only the player's save and starts empty, so each file is a separate playthrough. Work is saved automatically so players can close it and continue later:
141
+
142
+ ```json
143
+ {
144
+ "progress": {
145
+ "currentLevel": "first-steps",
146
+ "solved": ["first-steps"],
147
+ "code": { "first-steps": "step(300)\n" }
148
+ }
149
+ }
150
+ ```
151
+
152
+ Sharing a file also shares the player's answers.
@@ -0,0 +1,134 @@
1
+ <div align="center">
2
+ <img src="docs/grep-fox.png" width="140" alt="Grep Fox">
3
+ <img src="docs/sudo-snake.svg" width="140" alt="Sudo Snake">
4
+
5
+ <h1>FoxSnakeCode</h1>
6
+ <p><strong>Tactical Coding Action</strong></p>
7
+ <p>Coding missions, challenges, stealth debugging, boss levels...</p>
8
+ <p><em>Write Python. Slip past the searchlights. Steal the data.</em></p>
9
+ <p><a href="https://trungleduc.github.io/FoxSnakeCode/lab/"><strong>Try it in your browser</strong></a></p>
10
+ </div>
11
+
12
+ ## Meet the team
13
+
14
+ | | Codename | Role | |
15
+ | --- | --- | --- | --- |
16
+ | 🦊 | **Grep Fox** | Field agent | Sniffs out any word, in any file, in a flash. Your code tells Grep Fox where to go. |
17
+ | 🐍 | **Sudo Snake** | HQ | Sneaks past bugs and runs every command with superpowers. Briefs you on every mission. |
18
+
19
+ ## How it plays
20
+
21
+ 1. Click FoxSnakeCode in the launcher to start a new game, or double-click a saved `.fsc` file.
22
+ 2. Pick the next open level on the map. Solving a level unlocks the one after it, and every 10th level is a boss.
23
+ 3. Read your briefing from Sudo Snake.
24
+ 4. Write Python, then press Run.
25
+ 5. Watch Grep Fox dodge searchlights, lasers and decoys to grab every data chip.
26
+
27
+ FoxSnakeCode runs in JupyterLab and JupyterLite. Your code runs on a Python kernel, and xeus-python is preferred. The `foxsnakecode` package must be installed in the same environment as the kernel.
28
+
29
+ ## Hints from Sudo Snake
30
+
31
+ Press **Ask for a hint** during a mission to chat with Sudo Snake. Hints use [jupyter-ai-lite](https://github.com/jupyterlite/ai), so players connect their own AI provider or sign in with OpenRouter from **Set up AI**. By default the key is kept in memory and cleared when the page reloads. Never put your own API key in a deployed site, because anyone can read it.
32
+
33
+ Sudo Snake only sees the current level, the player's code and their last result, and has no tools. Its instructions keep it on the game and away from full solutions, but they run in the player's browser and are not a guarantee. The demo site turns off the general AI chat and code completion.
34
+
35
+ ## Install for development
36
+
37
+ ```bash
38
+ micromamba create -n cgs -c conda-forge python=3.12 'jupyterlab=4.*' 'nodejs=22' xeus-python jupyterlite-core jupyterlite-xeus pip
39
+ micromamba activate cgs
40
+ pip install -e .
41
+ jupyter labextension develop . --overwrite
42
+ jlpm install
43
+ jlpm build
44
+ jupyter lab
45
+ ```
46
+
47
+ Then click FoxSnakeCode in the launcher.
48
+
49
+ The game logic is in `foxsnakecode/engine.py` and the levels are in `foxsnakecode/missions.json`. After editing the engine, press Stop or restart the kernel to load the new code. After editing the levels, close and reopen the game.
50
+
51
+ ## JupyterLite demo site
52
+
53
+ The `demo` folder holds a JupyterLite site with xeus-python running in the browser. Build the site with the extension installed:
54
+
55
+ ```bash
56
+ pip install build hatchling hatch-nodejs-version hatch-jupyter-builder
57
+ jlpm build:demo
58
+ ```
59
+
60
+ This builds the `foxsnakecode` wheel and installs it into the site's kernel. The site is written to `demo/_output`, which you can host on any static web server.
61
+
62
+ After changing the extension, the Python package or the missions, `jlpm update:demo` copies them into an existing `demo/_output` without a full rebuild.
63
+
64
+ A local demo build keeps files in memory only, so nothing is saved in the browser and reloading the page loses any game you started.
65
+
66
+ The site deployed to GitHub Pages saves games in the player's browser instead.
67
+
68
+ Stop restarts the kernel, so the next Run can take a few seconds in JupyterLite.
69
+
70
+ ## Commands players can use
71
+
72
+ | Command | What it does |
73
+ | --- | --- |
74
+ | `step(distance)` | Walk forward. A negative number walks backward. |
75
+ | `turn(degrees)` | Turn right. A negative number turns left. |
76
+ | `turn_to(target)` | Face a chip, a guard or an `(x, y)` position. |
77
+ | `distance_to(target)` | Get the distance to a chip, a guard or an `(x, y)` position. |
78
+ | `wait(seconds)` | Stay still for a number of seconds. |
79
+ | `chips` | The list of chips. Each has `x`, `y`, `trapped` and `collected`. |
80
+ | `guards` | The list of guards. Each has `x`, `y` and `angle`, and they update as time passes. |
81
+
82
+ A level is solved when every chip that isn't trapped has been collected. Searchlights, lasers, trapped chips and being spotted by a guard end the attempt, while crates and walls just block the way.
83
+
84
+ ## Adding levels
85
+
86
+ Levels are in `foxsnakecode/missions.json`, and their order in the list is their order on the map. The world is 800 by 500 steps, with `x` increasing to the right and `y` increasing downward. An `angle` of 0 faces right.
87
+
88
+ ```json
89
+ {
90
+ "title": "FoxSnakeCode",
91
+ "levels": [
92
+ {
93
+ "id": "first-steps",
94
+ "title": "First Steps",
95
+ "instructions": "Reach the chip with `step`.",
96
+ "starterCode": "step(100)\n",
97
+ "scene": {
98
+ "start": { "x": 100, "y": 250, "angle": 0 },
99
+ "chips": [{ "x": 400, "y": 250 }, { "x": 600, "y": 250, "trapped": true }],
100
+ "obstacles": [{ "x": 300, "y": 50, "w": 100, "h": 100 }],
101
+ "hazards": [
102
+ { "x": 600, "y": 100, "r": 50 },
103
+ { "x": 200, "y": 400, "w": 300, "h": 6 }
104
+ ],
105
+ "guards": [
106
+ { "route": [{ "x": 200, "y": 300 }, { "x": 600, "y": 300 }], "speed": 80 }
107
+ ]
108
+ }
109
+ }
110
+ ]
111
+ }
112
+ ```
113
+
114
+ Each level needs a unique `id`. Saved games refer to levels by `id`, so never change one after release; new levels can go anywhere in the list without breaking saves. Add `"boss": true` to mark a boss level.
115
+
116
+ In `hazards`, an item with `r` is a searchlight and an item with `w` and `h` is a laser. Text between backticks in `instructions` is shown as code.
117
+
118
+ In `guards`, each guard walks its `route` at `speed` steps per second, then returns to the first point and starts again. Grep Fox is spotted inside a guard's vision cone or by touching the guard, and crates block the cone. Put guard routes where they don't pass through crates.
119
+
120
+ ## The `.fsc` file
121
+
122
+ A `.fsc` file holds only the player's save and starts empty, so each file is a separate playthrough. Work is saved automatically so players can close it and continue later:
123
+
124
+ ```json
125
+ {
126
+ "progress": {
127
+ "currentLevel": "first-steps",
128
+ "solved": ["first-steps"],
129
+ "code": { "first-steps": "step(300)\n" }
130
+ }
131
+ }
132
+ ```
133
+
134
+ Sharing a file also shares the player's answers.
@@ -0,0 +1,8 @@
1
+ name: xeus-kernels
2
+ channels:
3
+ - https://repo.prefix.dev/emscripten-forge-dev
4
+ - https://repo.prefix.dev/conda-forge
5
+ dependencies:
6
+ - xeus-python
7
+ - pip:
8
+ - ../dist/foxsnakecode-0.0.0-py3-none-any.whl
@@ -0,0 +1,16 @@
1
+ {
2
+ "jupyter-config-data": {
3
+ "enableMemoryStorage": true,
4
+ "contentsStorageDrivers": ["memoryStorageDriver"],
5
+ "disabledExtensions": [
6
+ "jupyterlab-chat-extension",
7
+ "@jupyter-ai/jupyternaut-lite:plugin",
8
+ "@jupyter-ai/jupyternaut-lite:mention",
9
+ "@jupyter-ai/jupyternaut-lite:skills-command",
10
+ "@jupyter-ai/jupyternaut-lite:stop-button",
11
+ "@jupyter-ai/jupyternaut-lite:chat-components-callbacks",
12
+ "@jupyter-ai/jupyternaut-lite:completion-status",
13
+ "@jupyterlab/completer-extension:inline-completer"
14
+ ]
15
+ }
16
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "LiteBuildConfig": {
3
+ "extra_file_types": {
4
+ "fsc": {
5
+ "name": "fsc",
6
+ "extensions": [".fsc"],
7
+ "mimeTypes": ["application/json"],
8
+ "fileFormat": "text"
9
+ }
10
+ }
11
+ }
12
+ }
Binary file
@@ -0,0 +1,41 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="480" height="480" viewBox="140 40 320 320" role="img" aria-label="Sudo Snake avatar: the snake's head in its hoodie on a yellow circle">
2
+ <defs>
3
+ <clipPath id="avatarClip"><circle cx="300" cy="200" r="158"></circle></clipPath>
4
+ </defs>
5
+ <circle cx="300" cy="200" r="158" fill="#FFC93C"></circle>
6
+ <g clip-path="url(#avatarClip)">
7
+ <path d="M 380 505 C 470 470 450 360 360 340 C 280 320 260 280 300 250" fill="none" stroke="#0F2E33" stroke-width="82" stroke-linecap="round"></path>
8
+ <path d="M 380 505 C 470 470 450 360 360 340 C 280 320 260 280 300 250" fill="none" stroke="#34C58F" stroke-width="66" stroke-linecap="round"></path>
9
+ <path d="M 380 505 C 470 470 450 360 360 340" fill="none" stroke="#C9F5DC" stroke-width="22" stroke-linecap="round"></path>
10
+ <path d="M 360 340 C 280 320 260 280 300 250" fill="none" stroke="#0F2E33" stroke-width="96" stroke-linecap="round"></path>
11
+ <path d="M 360 340 C 280 320 260 280 300 250" fill="none" stroke="#3D4A6B" stroke-width="82" stroke-linecap="round"></path>
12
+ <rect x="352" y="290" width="20" height="100" rx="10" fill="#3D4A6B" stroke="#0F2E33" stroke-width="5" transform="rotate(14 362 340)"></rect>
13
+ <rect x="352" y="290" width="20" height="100" rx="10" fill="#FFFFFF" opacity="0.14" transform="rotate(14 362 340)"></rect>
14
+ <ellipse cx="300" cy="178" rx="132" ry="118" fill="#3D4A6B" stroke="#0F2E33" stroke-width="6"></ellipse>
15
+ <ellipse cx="300" cy="188" rx="112" ry="96" fill="#141A26"></ellipse>
16
+ <circle cx="311" cy="322" r="19" fill="#FFFFFF" stroke="#0F2E33" stroke-width="5"></circle>
17
+ <text x="311" y="331" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="24" font-weight="500" fill="#0F2E33">#</text>
18
+ <ellipse cx="300" cy="202" rx="100" ry="78" fill="#34C58F" stroke="#0F2E33" stroke-width="6"></ellipse>
19
+ <circle cx="276" cy="140" r="8" fill="#0F2E33" opacity="0.16"></circle>
20
+ <circle cx="322" cy="137" r="6" fill="#0F2E33" opacity="0.16"></circle>
21
+ <circle cx="300" cy="131" r="4" fill="#0F2E33" opacity="0.16"></circle>
22
+ <path d="M 205 222 Q 212 268 258 266" fill="none" stroke="#0F2E33" stroke-width="6" stroke-linecap="round"></path>
23
+ <circle cx="263" cy="266" r="8" fill="#0F2E33"></circle>
24
+ <circle cx="200" cy="205" r="17" fill="#FFC93C" stroke="#0F2E33" stroke-width="5"></circle>
25
+ <ellipse cx="262" cy="192" rx="25" ry="29" fill="#FFFFFF" stroke="#0F2E33" stroke-width="4"></ellipse>
26
+ <ellipse cx="338" cy="192" rx="25" ry="29" fill="#FFFFFF" stroke="#0F2E33" stroke-width="4"></ellipse>
27
+ <circle cx="269" cy="197" r="13" fill="#0F2E33"></circle>
28
+ <circle cx="345" cy="197" r="13" fill="#0F2E33"></circle>
29
+ <circle cx="274" cy="190" r="5" fill="#FFFFFF"></circle>
30
+ <circle cx="350" cy="190" r="5" fill="#FFFFFF"></circle>
31
+ <path d="M 236 152 Q 260 146 286 160" fill="none" stroke="#0F2E33" stroke-width="7" stroke-linecap="round"></path>
32
+ <path d="M 364 152 Q 340 146 314 160" fill="none" stroke="#0F2E33" stroke-width="7" stroke-linecap="round"></path>
33
+ <ellipse cx="232" cy="232" rx="13" ry="8" fill="#FF8FA3" opacity="0.6"></ellipse>
34
+ <ellipse cx="368" cy="232" rx="13" ry="8" fill="#FF8FA3" opacity="0.6"></ellipse>
35
+ <circle cx="292" cy="226" r="2.5" fill="#0F2E33"></circle>
36
+ <circle cx="308" cy="226" r="2.5" fill="#0F2E33"></circle>
37
+ <path d="M 280 240 Q 302 256 326 238" fill="none" stroke="#0F2E33" stroke-width="5" stroke-linecap="round"></path>
38
+ <path d="M 306 249 L 309 266 L 302 274 M 309 266 L 316 274" fill="none" stroke="#E5484D" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path>
39
+ </g>
40
+ <circle cx="300" cy="200" r="158" fill="none" stroke="#0F2E33" stroke-width="6"></circle>
41
+ </svg>
@@ -0,0 +1,8 @@
1
+ try:
2
+ from ._version import __version__
3
+ except ImportError:
4
+ __version__ = "dev"
5
+
6
+
7
+ def _jupyter_labextension_paths():
8
+ return [{"src": "labextension", "dest": "foxsnakecode"}]
@@ -0,0 +1,4 @@
1
+ # This file is auto-generated by Hatchling. As such, do not:
2
+ # - modify
3
+ # - track in version control e.g. be sure to add to .gitignore
4
+ __version__ = VERSION = '1.0.0'