diff --git a/.config/mise.toml b/.config/mise.toml
index e52f235..10e5b52 100644
--- a/.config/mise.toml
+++ b/.config/mise.toml
@@ -1,5 +1,10 @@
experimental_monorepo_root = true
+[monorepo]
+config_roots = [
+ "crates/template/.config"
+]
+
[env]
_.source = ".config/env.sh"
diff --git a/crates/template/CHANGELOG.md b/crates/app/CHANGELOG.md
similarity index 100%
rename from crates/template/CHANGELOG.md
rename to crates/app/CHANGELOG.md
diff --git a/crates/template/Cargo.toml b/crates/app/Cargo.toml
similarity index 100%
rename from crates/template/Cargo.toml
rename to crates/app/Cargo.toml
diff --git a/crates/template/README.md b/crates/app/README.md
similarity index 70%
rename from crates/template/README.md
rename to crates/app/README.md
index 74714fd..d55f5d0 100644
--- a/crates/template/README.md
+++ b/crates/app/README.md
@@ -1,10 +1,4 @@
-
-

-
-
-This is a template-based template for a bevy project. It is a simplification of the work done for [q_service.](https://github.com/ada-x64/q_service)
-
-_This continues the work started [here.](https://github.com/ada-x64/tfw)_
+app
## Goals
diff --git a/crates/template/build.rs b/crates/app/build.rs
similarity index 100%
rename from crates/template/build.rs
rename to crates/app/build.rs
diff --git a/crates/template/src/clap.rs b/crates/app/src/clap.rs
similarity index 100%
rename from crates/template/src/clap.rs
rename to crates/app/src/clap.rs
diff --git a/crates/template/src/docs/architecture.md b/crates/app/src/docs/architecture.md
similarity index 100%
rename from crates/template/src/docs/architecture.md
rename to crates/app/src/docs/architecture.md
diff --git a/crates/template/src/docs/cli.md b/crates/app/src/docs/cli.md
similarity index 100%
rename from crates/template/src/docs/cli.md
rename to crates/app/src/docs/cli.md
diff --git a/crates/template/src/docs/events_systems_scopes.md b/crates/app/src/docs/events_systems_scopes.md
similarity index 100%
rename from crates/template/src/docs/events_systems_scopes.md
rename to crates/app/src/docs/events_systems_scopes.md
diff --git a/crates/template/src/docs/mod.rs b/crates/app/src/docs/mod.rs
similarity index 100%
rename from crates/template/src/docs/mod.rs
rename to crates/app/src/docs/mod.rs
diff --git a/crates/template/src/lib.rs b/crates/app/src/lib.rs
similarity index 100%
rename from crates/template/src/lib.rs
rename to crates/app/src/lib.rs
diff --git a/crates/template/src/main.rs b/crates/app/src/main.rs
similarity index 100%
rename from crates/template/src/main.rs
rename to crates/app/src/main.rs
diff --git a/crates/template/src/plugin.rs b/crates/app/src/plugin.rs
similarity index 100%
rename from crates/template/src/plugin.rs
rename to crates/app/src/plugin.rs
diff --git a/crates/template/src/screen/dev/camera_test/data.rs b/crates/app/src/screen/dev/camera_test/data.rs
similarity index 100%
rename from crates/template/src/screen/dev/camera_test/data.rs
rename to crates/app/src/screen/dev/camera_test/data.rs
diff --git a/crates/template/src/screen/dev/camera_test/mod.rs b/crates/app/src/screen/dev/camera_test/mod.rs
similarity index 100%
rename from crates/template/src/screen/dev/camera_test/mod.rs
rename to crates/app/src/screen/dev/camera_test/mod.rs
diff --git a/crates/template/src/screen/dev/camera_test/screen.rs b/crates/app/src/screen/dev/camera_test/screen.rs
similarity index 100%
rename from crates/template/src/screen/dev/camera_test/screen.rs
rename to crates/app/src/screen/dev/camera_test/screen.rs
diff --git a/crates/template/src/screen/dev/mod.rs b/crates/app/src/screen/dev/mod.rs
similarity index 100%
rename from crates/template/src/screen/dev/mod.rs
rename to crates/app/src/screen/dev/mod.rs
diff --git a/crates/template/src/screen/mod.rs b/crates/app/src/screen/mod.rs
similarity index 100%
rename from crates/template/src/screen/mod.rs
rename to crates/app/src/screen/mod.rs
diff --git a/crates/template/src/screen/splash/mod.rs b/crates/app/src/screen/splash/mod.rs
similarity index 100%
rename from crates/template/src/screen/splash/mod.rs
rename to crates/app/src/screen/splash/mod.rs
diff --git a/crates/template/src/screen/splash/state.rs b/crates/app/src/screen/splash/state.rs
similarity index 100%
rename from crates/template/src/screen/splash/state.rs
rename to crates/app/src/screen/splash/state.rs
diff --git a/crates/template/src/screen/splash/systems.rs b/crates/app/src/screen/splash/systems.rs
similarity index 100%
rename from crates/template/src/screen/splash/systems.rs
rename to crates/app/src/screen/splash/systems.rs
diff --git a/crates/template/src/screen/util.rs b/crates/app/src/screen/util.rs
similarity index 100%
rename from crates/template/src/screen/util.rs
rename to crates/app/src/screen/util.rs
diff --git a/crates/template/src/screen/world/mod.rs b/crates/app/src/screen/world/mod.rs
similarity index 100%
rename from crates/template/src/screen/world/mod.rs
rename to crates/app/src/screen/world/mod.rs
diff --git a/crates/template/src/screen/world/screen.rs b/crates/app/src/screen/world/screen.rs
similarity index 100%
rename from crates/template/src/screen/world/screen.rs
rename to crates/app/src/screen/world/screen.rs
diff --git a/crates/template/src/service/data.rs b/crates/app/src/service/data.rs
similarity index 100%
rename from crates/template/src/service/data.rs
rename to crates/app/src/service/data.rs
diff --git a/crates/template/src/service/dev/gizmos/data.rs b/crates/app/src/service/dev/gizmos/data.rs
similarity index 100%
rename from crates/template/src/service/dev/gizmos/data.rs
rename to crates/app/src/service/dev/gizmos/data.rs
diff --git a/crates/template/src/service/dev/gizmos/mod.rs b/crates/app/src/service/dev/gizmos/mod.rs
similarity index 100%
rename from crates/template/src/service/dev/gizmos/mod.rs
rename to crates/app/src/service/dev/gizmos/mod.rs
diff --git a/crates/template/src/service/dev/gizmos/systems.rs b/crates/app/src/service/dev/gizmos/systems.rs
similarity index 100%
rename from crates/template/src/service/dev/gizmos/systems.rs
rename to crates/app/src/service/dev/gizmos/systems.rs
diff --git a/crates/template/src/service/dev/mod.rs b/crates/app/src/service/dev/mod.rs
similarity index 100%
rename from crates/template/src/service/dev/mod.rs
rename to crates/app/src/service/dev/mod.rs
diff --git a/crates/template/src/service/input/camera/controller/data.rs b/crates/app/src/service/input/camera/controller/data.rs
similarity index 100%
rename from crates/template/src/service/input/camera/controller/data.rs
rename to crates/app/src/service/input/camera/controller/data.rs
diff --git a/crates/template/src/service/input/camera/controller/events.rs b/crates/app/src/service/input/camera/controller/events.rs
similarity index 100%
rename from crates/template/src/service/input/camera/controller/events.rs
rename to crates/app/src/service/input/camera/controller/events.rs
diff --git a/crates/template/src/service/input/camera/controller/mod.rs b/crates/app/src/service/input/camera/controller/mod.rs
similarity index 100%
rename from crates/template/src/service/input/camera/controller/mod.rs
rename to crates/app/src/service/input/camera/controller/mod.rs
diff --git a/crates/template/src/service/input/camera/data/input_ctx.rs b/crates/app/src/service/input/camera/data/input_ctx.rs
similarity index 100%
rename from crates/template/src/service/input/camera/data/input_ctx.rs
rename to crates/app/src/service/input/camera/data/input_ctx.rs
diff --git a/crates/template/src/service/input/camera/data/mod.rs b/crates/app/src/service/input/camera/data/mod.rs
similarity index 100%
rename from crates/template/src/service/input/camera/data/mod.rs
rename to crates/app/src/service/input/camera/data/mod.rs
diff --git a/crates/template/src/service/input/camera/fly/bundle.rs b/crates/app/src/service/input/camera/fly/bundle.rs
similarity index 100%
rename from crates/template/src/service/input/camera/fly/bundle.rs
rename to crates/app/src/service/input/camera/fly/bundle.rs
diff --git a/crates/template/src/service/input/camera/fly/data.rs b/crates/app/src/service/input/camera/fly/data.rs
similarity index 100%
rename from crates/template/src/service/input/camera/fly/data.rs
rename to crates/app/src/service/input/camera/fly/data.rs
diff --git a/crates/template/src/service/input/camera/fly/events.rs b/crates/app/src/service/input/camera/fly/events.rs
similarity index 100%
rename from crates/template/src/service/input/camera/fly/events.rs
rename to crates/app/src/service/input/camera/fly/events.rs
diff --git a/crates/template/src/service/input/camera/fly/mod.rs b/crates/app/src/service/input/camera/fly/mod.rs
similarity index 100%
rename from crates/template/src/service/input/camera/fly/mod.rs
rename to crates/app/src/service/input/camera/fly/mod.rs
diff --git a/crates/template/src/service/input/camera/mod.rs b/crates/app/src/service/input/camera/mod.rs
similarity index 100%
rename from crates/template/src/service/input/camera/mod.rs
rename to crates/app/src/service/input/camera/mod.rs
diff --git a/crates/template/src/service/input/camera/tracking/bundle.rs b/crates/app/src/service/input/camera/tracking/bundle.rs
similarity index 100%
rename from crates/template/src/service/input/camera/tracking/bundle.rs
rename to crates/app/src/service/input/camera/tracking/bundle.rs
diff --git a/crates/template/src/service/input/camera/tracking/data.rs b/crates/app/src/service/input/camera/tracking/data.rs
similarity index 100%
rename from crates/template/src/service/input/camera/tracking/data.rs
rename to crates/app/src/service/input/camera/tracking/data.rs
diff --git a/crates/template/src/service/input/camera/tracking/events.rs b/crates/app/src/service/input/camera/tracking/events.rs
similarity index 100%
rename from crates/template/src/service/input/camera/tracking/events.rs
rename to crates/app/src/service/input/camera/tracking/events.rs
diff --git a/crates/template/src/service/input/camera/tracking/mod.rs b/crates/app/src/service/input/camera/tracking/mod.rs
similarity index 100%
rename from crates/template/src/service/input/camera/tracking/mod.rs
rename to crates/app/src/service/input/camera/tracking/mod.rs
diff --git a/crates/template/src/service/input/camera/tracking/systems.rs b/crates/app/src/service/input/camera/tracking/systems.rs
similarity index 100%
rename from crates/template/src/service/input/camera/tracking/systems.rs
rename to crates/app/src/service/input/camera/tracking/systems.rs
diff --git a/crates/template/src/service/input/cursor/data.rs b/crates/app/src/service/input/cursor/data.rs
similarity index 100%
rename from crates/template/src/service/input/cursor/data.rs
rename to crates/app/src/service/input/cursor/data.rs
diff --git a/crates/template/src/service/input/cursor/events.rs b/crates/app/src/service/input/cursor/events.rs
similarity index 100%
rename from crates/template/src/service/input/cursor/events.rs
rename to crates/app/src/service/input/cursor/events.rs
diff --git a/crates/template/src/service/input/cursor/mod.rs b/crates/app/src/service/input/cursor/mod.rs
similarity index 100%
rename from crates/template/src/service/input/cursor/mod.rs
rename to crates/app/src/service/input/cursor/mod.rs
diff --git a/crates/template/src/service/input/data.rs b/crates/app/src/service/input/data.rs
similarity index 100%
rename from crates/template/src/service/input/data.rs
rename to crates/app/src/service/input/data.rs
diff --git a/crates/template/src/service/input/events.rs b/crates/app/src/service/input/events.rs
similarity index 100%
rename from crates/template/src/service/input/events.rs
rename to crates/app/src/service/input/events.rs
diff --git a/crates/template/src/service/input/mod.rs b/crates/app/src/service/input/mod.rs
similarity index 100%
rename from crates/template/src/service/input/mod.rs
rename to crates/app/src/service/input/mod.rs
diff --git a/crates/template/src/service/mod.rs b/crates/app/src/service/mod.rs
similarity index 100%
rename from crates/template/src/service/mod.rs
rename to crates/app/src/service/mod.rs
diff --git a/crates/template/src/service/player/data.rs b/crates/app/src/service/player/data.rs
similarity index 100%
rename from crates/template/src/service/player/data.rs
rename to crates/app/src/service/player/data.rs
diff --git a/crates/template/src/service/player/events.rs b/crates/app/src/service/player/events.rs
similarity index 100%
rename from crates/template/src/service/player/events.rs
rename to crates/app/src/service/player/events.rs
diff --git a/crates/template/src/service/player/mod.rs b/crates/app/src/service/player/mod.rs
similarity index 100%
rename from crates/template/src/service/player/mod.rs
rename to crates/app/src/service/player/mod.rs
diff --git a/crates/template/src/service/player/systems.rs b/crates/app/src/service/player/systems.rs
similarity index 100%
rename from crates/template/src/service/player/systems.rs
rename to crates/app/src/service/player/systems.rs
diff --git a/crates/template/src/service/text/mod.rs b/crates/app/src/service/text/mod.rs
similarity index 100%
rename from crates/template/src/service/text/mod.rs
rename to crates/app/src/service/text/mod.rs
diff --git a/crates/template/src/service/third_party.rs b/crates/app/src/service/third_party.rs
similarity index 100%
rename from crates/template/src/service/third_party.rs
rename to crates/app/src/service/third_party.rs
diff --git a/crates/template/src/service/ui/mod.rs b/crates/app/src/service/ui/mod.rs
similarity index 100%
rename from crates/template/src/service/ui/mod.rs
rename to crates/app/src/service/ui/mod.rs
diff --git a/crates/template/src/service/util.rs b/crates/app/src/service/util.rs
similarity index 100%
rename from crates/template/src/service/util.rs
rename to crates/app/src/service/util.rs
diff --git a/crates/template/src/service/worldgen/data.rs b/crates/app/src/service/worldgen/data.rs
similarity index 100%
rename from crates/template/src/service/worldgen/data.rs
rename to crates/app/src/service/worldgen/data.rs
diff --git a/crates/template/src/service/worldgen/mod.rs b/crates/app/src/service/worldgen/mod.rs
similarity index 100%
rename from crates/template/src/service/worldgen/mod.rs
rename to crates/app/src/service/worldgen/mod.rs
diff --git a/crates/template/.config/mise.toml b/crates/template/.config/mise.toml
deleted file mode 100644
index 7d6d407..0000000
--- a/crates/template/.config/mise.toml
+++ /dev/null
@@ -1,110 +0,0 @@
-# GENERATION ##################################################################
-
-[tasks.new]
-raw=true
-alias=['generate', 'n']
-description="Generate a new service or screen."
-tools={"cargo:cargo-generate" = "latest"}
-usage = '''
-arg "" help="The template to generate." {
- choices "screen" "service"
-}
-
-arg "" help="Name of the generated module." long_help="""
-The chosen template will be output to the src directory corresponding to the
-template, postfixed with given template name. For example, calling
-'mise new service foo/bar' will generate 'src/service/foo/bar/...'.
-"""
-
-flag "--base-path " help="Base path for the project. Scripts expect modules named '$BASE_PATH/${service, screen}' Defaults to 'src'" default="src"
-
-flag "--debug" help="Enable debug output."
-'''
-run='''
-#!/usr/bin/bash
-TEMPLATE=${usage_template?}
-NAME=${usage_name?}
-DEBUG=${usage_debug:+--debug}
-BASE_PATH=${usage_base_path?}
-
-BASENAME=$(basename $NAME)
-DESTINATION="$(realpath $BASE_PATH/$TEMPLATE/$(dirname $NAME))"
-
-if [[ -n "$DEBUG" ]]; then
-cat <" help="The template to remove." {
- choices "screen" "service"
-}
-
-arg "" help="Name of the generated module." long_help="""
-The chosen template will be removed from the src directory corresponding to the
-template, postfixed with given template name. For example, calling
-'mise new service foo/bar' will generate 'src/service/foo/bar/...'.
-"""
-
-flag "--base-path " help="Base path for the project. Scripts expect modules named '$BASE_PATH/${service, screen}' Defaults to 'src'" default="src"
-
-flag "--debug" help="Enable debug output."
-'''
-run='''
-#!/usr/bin/bash
-set -e
-TEMPLATE=${usage_template?}
-NAME=${usage_name?}
-BASE_PATH=${usage_base_path?}
-DESTINATION="$(realpath $BASE_PATH/$TEMPLATE/$NAME)"
-DEBUG=${usage_debug:+--debug}
-
-uv run .config/scripts/new_mod/main.py\
- "$DESTINATION" \
- --remove \
- $DEBUG
-
-set -x
-rm -r $DESTINATION
-set +x
-
-echo "[INFO] Formatting ..."
-cargo fmt -- -l;
-'''
diff --git a/crates/template/.config/scripts/.python-version b/crates/template/.config/scripts/.python-version
deleted file mode 100644
index 24ee5b1..0000000
--- a/crates/template/.config/scripts/.python-version
+++ /dev/null
@@ -1 +0,0 @@
-3.13
diff --git a/crates/template/.config/scripts/new_mod/main.py b/crates/template/.config/scripts/new_mod/main.py
deleted file mode 100644
index 091eafb..0000000
--- a/crates/template/.config/scripts/new_mod/main.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import argparse
-from util import get_vars, add_module, remove_module, Args
-import util
-from typing import cast
-
-# parse args
-parser = argparse.ArgumentParser(prog="update_parent_module")
-_ = parser.add_argument("base-path")
-_ = parser.add_argument("--debug", action="store_true")
-_ = parser.add_argument("--remove", action="store_true")
-args = parser.parse_args()
-args = cast(Args, args)
-
-get_vars(args)
-vars = util.vars
-
-# modify super module
-util.read(vars.super_mod)
-if args.remove:
- remove_module()
-else:
- add_module()
-util.write(vars.super_mod)
-
-# update screen enum
-if vars.is_screen:
- util.read(vars.screens_data_mod)
- if args.remove:
- util.re_replace(
- vars.screens_exists_expr,
- "",
- "Could not find screen name in Screens enum. Please remove the screen manually, if it exists.",
- )
- util.re_replace(
- vars.screens_pat_expr,
- "",
- "Could not find screen name in Screens impl. Please remove the screen manually, if it exists.",
- )
- else:
- util.insert_after(
- [vars.screens_expr],
- vars.screens_str,
- "Could not find Screens enum. Please register the screen manually.",
- )
- util.insert_after(
- [vars.screens_match_expr],
- vars.screens_pat,
- "Could not find screen conversion fn. Please insert manually.",
- )
- util.write(vars.screens_data_mod)
diff --git a/crates/template/.config/scripts/new_mod/util.py b/crates/template/.config/scripts/new_mod/util.py
deleted file mode 100644
index db5fc70..0000000
--- a/crates/template/.config/scripts/new_mod/util.py
+++ /dev/null
@@ -1,159 +0,0 @@
-from os import PathLike, fspath, path, stat
-import re
-from dataclasses import dataclass, asdict
-from os.path import basename, join, realpath
-from re import Match, Pattern
-from pprint import pformat
-import logging
-import argparse
-
-type Expr = Pattern[str]
-
-
-@dataclass
-class Args(argparse.Namespace):
- base_path: PathLike[str] | None
- remove: bool
- debug: bool
-
-
-@dataclass
-class Vars:
- use_expr: Expr
- mod_expr: Expr
- prelude_expr: Expr
- plugin_expr: Expr
- screens_expr: Expr
- screens_pat_expr: Expr
- screens_match_expr: Expr
- screens_exists_expr: Expr
- screens_data_mod: str
- super_mod: str
- mod_name: str
- mod_str: str
- prelude_str: str
- plugin_str: str
- screens_str: str
- screens_pat: str
- file_str: str
- is_screen: bool
-
-
-def get_vars(args: Args):
- global vars, logger
-
- logging.basicConfig(
- level=logging.DEBUG if args.debug else logging.INFO,
- format="[%(levelname)s] %(message)s",
- )
- logger = logging.getLogger(__name__)
-
- if args.base_path is None:
- logger.error("Please provide a module path.\n")
- exit(1)
-
- mod_name = basename(args.base_path)
- mod_camel_case = mod_name.replace("_", " ").title().replace(" ", "")
- vars = Vars(
- use_expr=re.compile(r"(\s*use\s+[\w:]+;\n?)+"),
- mod_expr=re.compile(r"(\s*mod\s+\w+;\n?)+"),
- prelude_expr=re.compile(r"\s*pub mod prelude \{"),
- plugin_expr=re.compile(r"\s*pub fn plugin\(_?\w+: &mut App\) \{[^}]*"),
- screens_expr=re.compile(r"enum Screens \{[^}]*"),
- screens_exists_expr=re.compile(rf"\s+{mod_camel_case},?\s+"),
- screens_pat_expr=re.compile(rf"Screens::{mod_camel_case}\s+=>\s+\"\w+\",?"),
- screens_match_expr=re.compile(
- r"pub\s+const\s+fn\s+as_screen_type\(self\)\s+->\s+ScreenId\s+\{\n.+match self \{"
- ),
- screens_data_mod=realpath(join(args.base_path, "../data.rs")),
- super_mod=realpath(join(args.base_path, "../mod.rs")),
- mod_name=mod_name,
- mod_str=f"mod {mod_name};",
- prelude_str=f"pub use super::{mod_name}::prelude::*;",
- plugin_str=f"app.add_plugins({mod_name}::plugin);",
- screens_str=f"{mod_camel_case},",
- screens_pat=f'Screens::{mod_camel_case} => "{mod_name}",',
- file_str="",
- is_screen="/screen" in fspath(args.base_path),
- )
-
- if args.debug:
- logger.debug(pformat(asdict(vars)))
-
-
-def add_module():
- global vars
- ms = vars.mod_str.center(len(vars.mod_str) + 2)
- prs = vars.prelude_str.center(len(vars.prelude_str) + 2)
- pls = vars.plugin_str.center(len(vars.plugin_str) + 2)
-
- if not try_insert_after([vars.mod_expr, vars.use_expr], ms):
- insert(0, ms)
-
- insert_after(
- [vars.prelude_expr], prs, "No prelude found, not exposing new module's prelude"
- )
- insert_after(
- [vars.plugin_expr],
- pls,
- "Could not find plugin insertion point, please insert the plugin manually.",
- )
-
-
-def remove_module():
- global vars
- replace(vars.mod_str, "")
- replace(vars.prelude_str, "")
- replace(vars.plugin_str, "")
-
-
-def insert(pos: int, inserted_str: str):
- global vars
- vars.file_str = vars.file_str[:pos] + inserted_str + vars.file_str[pos:]
-
-
-def read(file: str):
- global vars
- with open(file) as buf:
- vars.file_str = buf.read()
-
-
-def write(file: str):
- global vars
- with open(file, "w") as buf:
- logger.info(f"Writing to {file}")
- _ = buf.write(vars.file_str)
-
-
-def replace(match: str, replace: str):
- vars.file_str = vars.file_str.replace(match, replace)
-
-
-def re_replace(pattern: Expr, replace: str, msg_on_err: str):
- if match := find([pattern]):
- vars.file_str = vars.file_str.replace(match.group(0), replace)
- else:
- logger.warning(msg_on_err)
-
-
-def find(exprs: list[Expr]) -> Match[str] | None:
- for expr in exprs:
- if match := expr.search(vars.file_str, re.MULTILINE):
- return match
- return None
-
-
-def try_insert_after(exprs: list[Expr], replace: str) -> bool:
- global vars
- if match := find(exprs):
- insert(match.end(), replace)
- return True
- return False
-
-
-def insert_after(exprs: list[Expr], replace: str, msg_on_err: str):
- global vars
- if match := find(exprs):
- insert(match.end(), replace)
- else:
- logger.warning(msg_on_err)
diff --git a/crates/template/.config/scripts/pyproject.toml b/crates/template/.config/scripts/pyproject.toml
deleted file mode 100644
index d70d655..0000000
--- a/crates/template/.config/scripts/pyproject.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[project]
-name = "scripts"
-version = "0.1.0"
-requires-python = ">=3.13"
-dependencies = []
-
-[tool.basedpyright]
-include= ["./"]
-exclude=["**/__pycache__"]
-executionEnvironments = [
- {root="."}
-]
diff --git a/crates/template/.config/templates/screen/cargo-generate.toml b/crates/template/.config/templates/screen/cargo-generate.toml
deleted file mode 100644
index f16b808..0000000
--- a/crates/template/.config/templates/screen/cargo-generate.toml
+++ /dev/null
@@ -1,5 +0,0 @@
-[placeholders]
-name = {type="string", prompt="Screen name?", default="screen"}
-assets = {type="bool", prompt="Require assets?" }
-settings = {type="bool", prompt="Require settings?" }
-strategy = {type="string", prompt="Loading strategy?", choices=["Blocking", "NonBlocking"] }
diff --git a/crates/template/.config/templates/screen/mod.rs.liquid b/crates/template/.config/templates/screen/mod.rs.liquid
deleted file mode 100644
index c1d2f01..0000000
--- a/crates/template/.config/templates/screen/mod.rs.liquid
+++ /dev/null
@@ -1,20 +0,0 @@
-{%- assign settings_name = name | upper_camel_case | append: "Settings" -%}
-{%- assign screen_name = name | upper_camel_case | append: "Screen" -%}
-{%- assign screen_name = name | upper_camel_case | append: "Assets" -%}
-use crate::prelude::*;
-
-mod screen;
-pub mod prelude {
- pub use super::screen::{ {{screen_name}}
- {%- if settings -%}
- , {{settings_name}}
- {%- endif -%}
- {%- if assets -%}
- , {{assets_name}}
- {%- endif -%}
- };
-}
-
-pub fn plugin(app: &mut App) {
- app.add_plugins(screen::plugin);
-}
diff --git a/crates/template/.config/templates/screen/screen.rs.liquid b/crates/template/.config/templates/screen/screen.rs.liquid
deleted file mode 100644
index 3ebf050..0000000
--- a/crates/template/.config/templates/screen/screen.rs.liquid
+++ /dev/null
@@ -1,34 +0,0 @@
-{%- assign settings_name = name | upper_camel_case | append: "Settings" -%}
-{%- assign screen_name = name | upper_camel_case | append: "Screen" -%}
-{%- assign assets_name = name | upper_camel_case | append: "Assets" -%}
-use crate::prelude::*;
-
-{% if settings %}
-#[derive(PartialEq, Eq, Clone, Debug, Hash, Reflect, Default, Resource)]
-pub struct {{settings_name -}};
-{%- endif %}
-
-{% if assets %}
-#[derive(AssetCollection, Resource, Debug, Default)]
-pub struct {{assets_name -}} {
- // some assets ...
- // see bevy_asset_loader docs
- // https://docs.rs/bevy_asset_loader/latest/bevy_asset_loader/
-}
-{%- endif %}
-
-#[derive(Component, Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Reflect)]
-pub struct {{screen_name -}};
-impl Screen for {{screen_name}} {
- type SETTINGS = {% if settings -%} {{- settings_name -}} {%- else -%} NoSettings {%- endif -%};
- type ASSETS = {% if assets -%} {{- assets_name -}} {%- else -%} NoAssets {%- endif %};
- const STRATEGY: LoadingStrategy = LoadingStrategy::{{strategy -}};
-}
-
-pub fn plugin(app: &mut App) {
- ScreenScopeBuilder::<{{screen_name}}>::new(app)
- // .add_systems(some_service_systems().take())
- // .on_ready(init)
- // .on_unload(unload)
- .build();
-}
diff --git a/crates/template/.config/templates/service/bundle.rs.liquid b/crates/template/.config/templates/service/bundle.rs.liquid
deleted file mode 100644
index 2c923b6..0000000
--- a/crates/template/.config/templates/service/bundle.rs.liquid
+++ /dev/null
@@ -1,10 +0,0 @@
-{%- assign title = name | title_case -%}
-{%- assign bundle_marker = name | upper_camel_case | append: "BundleMarker" -%}
-use crate::prelude::*;
-
-// We use functions to initialize bundles because they are more flexible than
-// struct types.
-/// Use this function to initialize a {{title}} bundle.
-pub fn bundle() -> impl Bundle {
- ({{bundle_marker}})
-}
diff --git a/crates/template/.config/templates/service/cargo-generate.toml b/crates/template/.config/templates/service/cargo-generate.toml
deleted file mode 100644
index 1f2303a..0000000
--- a/crates/template/.config/templates/service/cargo-generate.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-[placeholders]
-name = {type="string", prompt="Service name?", default="service"}
-use_bundle = {type="bool", prompt="Include a bundle?", default=false}
-use_systems = {type="bool", prompt="Include systems?", default=false}
-use_events = {type="bool", prompt="Include events?", default=true}
-
-[conditional.'!use_bundle']
-ignore= [ 'bundle.rs' ]
-
-[conditional.'!use_systems']
-ignore= [ 'systems.rs' ]
-
-[conditional.'!use_events']
-ignore= [ 'events.rs' ]
diff --git a/crates/template/.config/templates/service/data.rs.liquid b/crates/template/.config/templates/service/data.rs.liquid
deleted file mode 100644
index 2ed1aac..0000000
--- a/crates/template/.config/templates/service/data.rs.liquid
+++ /dev/null
@@ -1,15 +0,0 @@
-use crate::prelude::*;
-
-// Add all your data types here.
-// That includes all helper types, components, and their derivatives
-// (e.g. Resources, Events)
-
-{% if use_bundle -%}
-#[derive(Component, Default, Debug, Reflect)]
-pub struct {{name | upper_camel_case | append: "BundleMarker"}};
-{%- endif %}
-
-{% if use_events -%}
-#[derive(Event, Default, Debug, Reflect)]
-pub struct {{name | upper_camel_case | append: "Event"}};
-{%- endif %}
diff --git a/crates/template/.config/templates/service/events.rs.liquid b/crates/template/.config/templates/service/events.rs.liquid
deleted file mode 100644
index 2d2edf0..0000000
--- a/crates/template/.config/templates/service/events.rs.liquid
+++ /dev/null
@@ -1,9 +0,0 @@
-use crate::prelude::*;
-
-fn on_event(trigger: On<{{name | upper_camel_case | append: "Event"}}>) {
- // Replace me!
-}
-
-pub fn plugin(app: &mut App) {
- app.add_observer(on_event);
-}
diff --git a/crates/template/.config/templates/service/mod.rs.liquid b/crates/template/.config/templates/service/mod.rs.liquid
deleted file mode 100644
index c04e2fc..0000000
--- a/crates/template/.config/templates/service/mod.rs.liquid
+++ /dev/null
@@ -1,34 +0,0 @@
-{%- assign name = name | snake_case -%}
-use crate::prelude::*;
-
-{% if use_bundle -%}
-mod bundle;
-{%- endif %}
-{% if use_events -%}
-mod events;
-{%- endif %}
-{% if use_systems -%}
-mod systems;
-{%- endif %}
-mod data;
-
-pub mod prelude {
- pub use super::data::*;
- {% if use_bundle -%}
- pub use super::bundle::bundle as {{name | append: "_bundle" }};
- {%- endif -%}
- {% if use_systems -%}
- pub use super::systems::systems as {{name | append: "_systems" }};
- {%- endif -%}
- // pub use super::my_submodule::prelude::*;
-}
-
-pub fn plugin(app: &mut App) {
- {% if use_events %}
- app.add_plugins(
- events::plugin
- );
- {%- else %}
- // app.add_plugins(/* ... */);
- {% endif -%}
-}
diff --git a/crates/template/.config/templates/service/systems.rs.liquid b/crates/template/.config/templates/service/systems.rs.liquid
deleted file mode 100644
index 48a2c73..0000000
--- a/crates/template/.config/templates/service/systems.rs.liquid
+++ /dev/null
@@ -1,10 +0,0 @@
-use crate::prelude::*;
-
-pub fn example() {
- // replace me!
-}
-
-/// Add this function to any screens which need to use this service.
-pub fn systems() -> ServiceSystems {
- ServiceSystems::new((example))
-}
diff --git a/crates/template/.github/workflows/ci.yaml b/crates/template/.github/workflows/ci.yaml
deleted file mode 100644
index 3ccb05f..0000000
--- a/crates/template/.github/workflows/ci.yaml
+++ /dev/null
@@ -1,54 +0,0 @@
-name: Cargo Build & Test
-
-on:
- push:
-
-env:
- CARGO_TERM_COLOR: always
-
-jobs:
- build_and_test:
- runs-on: ubuntu-24.04
- env:
- CARGO_TERM_COLOR: always
- strategy:
- matrix:
- target: [x86_64-pc-windows-msvc, x86_64-unknown-linux-gnu]
- steps:
- - uses: actions/checkout@v4
- with:
- submodules: recursive
-
- - name: Cache
- uses: actions/cache@v4
- with:
- path: |
- ~/.cargo/bin/
- ~/.cargo/registry/index/
- ~/.cargo/registry/cache/
- ~/.cargo/git/db/
- target/
- key: ${{ matrix.target }}-ci-${{ hashFiles('**/Cargo.toml') }}
-
- - name: Install dependencies
- shell: bash
- run: >
- sudo apt-get update;
- sudo apt-get install -y --no-install-recommends
- libasound2-dev
- libudev-dev
- libwayland-dev
- ;
-
- - name: Install rust
- uses: actions-rust-lang/setup-rust-toolchain@v1
- with:
- toolchain: nightly-2026-01-22
- components: rustc-codegen-cranelift-preview,rustc-dev,llvm-tools-preview,clippy
-
- - uses: jdx/mise-action@v3
- with:
- log_level: info
-
- - run: "rustup component list --installed"
- - run: "RUST_BACKTRACE=1 RUST_LOG=app=debug,tfw=debug MISE_ENV=ci mise check ::: test"
diff --git a/crates/template/.zed/debug.json b/crates/template/.zed/debug.json
deleted file mode 100644
index 601cfd9..0000000
--- a/crates/template/.zed/debug.json
+++ /dev/null
@@ -1,15 +0,0 @@
-// Project-local debug tasks
-//
-// For more documentation on how to configure debug tasks,
-// see: https://zed.dev/docs/debugger
-[
- {
- "label": "Debug game",
- "adapter": "CodeLLDB",
- "build": {
- "command": "cargo",
- "args": ["build"]
- },
- "sourceLanguages": ["rust"]
- }
-]
diff --git a/crates/template/.zed/settings.json b/crates/template/.zed/settings.json
deleted file mode 100644
index f11efb2..0000000
--- a/crates/template/.zed/settings.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "lsp": {
- "rust-analyzer": {
- "initialization_options": {
- "cargo": {
- "features": "all"
- },
- "check": {
- "command": "clippy",
- "extraArgs": [
- "--locked",
- "--target-dir=target/rust-analyzer"
- ]
- }
- }
- }
- },
- "languages": {
- "Python": {
- "language_servers": ["ruff", "pyright"]
- }
- }
-}
--
2.51.2
From 6d71831a79a33d3ac625241e5621be6e7c5dc5ea Mon Sep 17 00:00:00 2001
From: ada
Date: Fri, 6 Feb 2026 17:41:08 -0600
Subject: [PATCH 2/6] feat: basic console integration
---
.config/env.sh | 1 -
.config/mise.toml | 7 --
Cargo.lock | 2 +
crates/app/Cargo.toml | 2 +
crates/app/src/service/dev/console/mod.rs | 14 +++
crates/app/src/service/dev/console/ui.rs | 103 ++++++++++++++++++++++
crates/app/src/service/dev/mod.rs | 7 +-
crates/screens/src/systems.rs | 2 +-
8 files changed, 128 insertions(+), 10 deletions(-)
create mode 100644 crates/app/src/service/dev/console/mod.rs
create mode 100644 crates/app/src/service/dev/console/ui.rs
diff --git a/.config/env.sh b/.config/env.sh
index 94aa17c..6a30564 100644
--- a/.config/env.sh
+++ b/.config/env.sh
@@ -1,7 +1,6 @@
export CARGO_TERM_COLOR="always"
export PYTHONUNBUFFERED=1
export RUSTC_WRAPPER="sccache"
-export MISE_EXPERIMENTAL=1
if [[ -n "$SSH_CLIENT" ]]; then
export FEATURES=""
diff --git a/.config/mise.toml b/.config/mise.toml
index 10e5b52..9406067 100644
--- a/.config/mise.toml
+++ b/.config/mise.toml
@@ -1,10 +1,3 @@
-experimental_monorepo_root = true
-
-[monorepo]
-config_roots = [
- "crates/template/.config"
-]
-
[env]
_.source = ".config/env.sh"
diff --git a/Cargo.lock b/Cargo.lock
index 7d1d3c7..6eb56b5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -236,6 +236,7 @@ dependencies = [
"anyhow",
"avian3d",
"bevy",
+ "bevy-inspector-egui",
"bevy-tnua",
"bevy-tnua-avian3d",
"bevy_asset_loader",
@@ -246,6 +247,7 @@ dependencies = [
"built",
"clap",
"itertools 0.14.0",
+ "q_cmd_prompt",
"q_screens",
"serde",
"strum",
diff --git a/crates/app/Cargo.toml b/crates/app/Cargo.toml
index 119ad01..d4074fb 100644
--- a/crates/app/Cargo.toml
+++ b/crates/app/Cargo.toml
@@ -33,6 +33,8 @@ clap = {version = "4.5.54", features = ["derive"] }
# workspace
q_screens = {path = "../screens", version= "^0.1.0" }
+q_cmd_prompt = {path = "../cmd_prompt", version="^0.1.0"}
+bevy-inspector-egui = "0.36.0"
[build-dependencies]
built = {version = "0.8.0", features=["chrono"]}
diff --git a/crates/app/src/service/dev/console/mod.rs b/crates/app/src/service/dev/console/mod.rs
new file mode 100644
index 0000000..6490296
--- /dev/null
+++ b/crates/app/src/service/dev/console/mod.rs
@@ -0,0 +1,14 @@
+mod commands;
+mod ui;
+
+use crate::prelude::*;
+
+pub mod prelude {
+ pub use super::commands::*;
+ pub use super::ui::*;
+}
+
+pub fn plugin(app: &mut App) {
+ app.add_plugins(q_cmd_prompt::ConsolePlugin);
+ app.add_plugins((ui::plugin, commands::plugin));
+}
diff --git a/crates/app/src/service/dev/console/ui.rs b/crates/app/src/service/dev/console/ui.rs
new file mode 100644
index 0000000..2a47e1f
--- /dev/null
+++ b/crates/app/src/service/dev/console/ui.rs
@@ -0,0 +1,103 @@
+// add a bevy-ui based console wrapper here.
+// open and close with `
+
+use crate::prelude::*;
+use bevy::input_focus::InputFocus;
+use q_cmd_prompt::prelude::*;
+
+fn on_switch_screen(
+ trigger: On,
+ screens: Screens,
+ mut prompts: Query<&mut ConsolePrompt>,
+) {
+ for mut prompt in &mut prompts {
+ let screen_name = screens.get_by_id(trigger.to).unwrap().name();
+ prompt.0 = format!("<{screen_name}>\n> ");
+ }
+}
+
+fn toggle_console(
+ keys: Res>,
+ mut focus: ResMut,
+ mut consoles: Query<(Entity, &mut Visibility), With>,
+) {
+ if keys.just_pressed(KeyCode::Backquote)
+ && (keys.pressed(KeyCode::ControlLeft) || keys.pressed(KeyCode::ControlRight))
+ {
+ for (id, mut visibility) in consoles.iter_mut() {
+ match *visibility {
+ Visibility::Hidden => {
+ *visibility = Visibility::Visible;
+ focus.set(id);
+ debug!("Opening and focusing dev console.")
+ }
+ Visibility::Visible => {
+ *visibility = Visibility::Hidden;
+ if let Some(focus_id) = focus.0
+ && focus_id == id
+ {
+ focus.clear()
+ }
+ debug!("Closing dev console.")
+ }
+ _ => {
+ warn!("Got unsupported visibility: Inherited");
+ }
+ }
+ }
+ }
+}
+
+// this should really be an observer but AcquireFocus isn't publically accessible
+fn on_focus(
+ focus: Res,
+ console: Query<&ConsoleUiSettings>,
+ mut commands: Commands,
+ mut last_focus: Local