Glazed is a local ceramic tile glaze archive system. It helps users digitize tile boards, import cropped tile records into MariaDB, and search the archive with filters or local AI.
glazer_admin/: React annotation app for uploading board photos and drawing tile boxes.glaze_daemon/: FastAPI import service that receives annotation exports and writes to MariaDB.glazy_app/: Avalonia desktop search app.ai-search-prototype/: local CLIP-based natural-language search.compose.yaml: Podman Compose services for the frontend, backend, and MariaDB.
- Podman
- Podman Compose support, usually available as
podman compose - Node.js 18 or newer, only needed for local AI search or frontend development outside containers
- .NET SDK 8, only needed to build the desktop app
Clone with submodules:
git clone --recurse-submodules https://github.com/cacticouncil/glazed.git
cd glazedCreate local environment settings:
cp .env.example .envStart the services:
podman compose up -d --buildA fresh clone creates a new empty MariaDB volume. Import tile exports through the Glazer admin app, run the metadata backfill for older rows if needed, or restore a shared database dump if the team wants everyone to start with the same test data. Local AI model files, image samples, visual metrics, and embeddings are regenerated on each machine and are ignored by Git.
Open:
- Glazer admin app: http://localhost
- Glaze Daemon API docs: http://localhost:8000/docs
- MariaDB:
localhost:3306
Do not open localhost:3306 in a browser. It is the database protocol, not HTTP.
flowchart LR
A["Glazer admin app"] --> B["ZIP export in memory"]
B --> C["Glaze Daemon POST /upload"]
C --> D["MariaDB tilearchive database"]
D --> E["Glazy desktop app"]
D --> F["Local AI search"]
F --> E
Start or rebuild everything:
podman compose up -d --buildStop services:
podman compose downReset the database volume:
podman compose down -v
podman compose up -d --buildWarning: podman compose down -v deletes the local database volume.
View service logs:
podman compose logs glaze-daemon
podman compose logs tile-dbCheck tile count:
set -a
source .env
set +a
podman compose exec -T tile-db mariadb \
-u"$DB_USER" -p"$DB_PASSWORD" "$MYSQL_DATABASE" \
-e "SELECT COUNT(*) AS tiles FROM testpiece;"Location: glazer_admin/
The admin app is used to:
- Upload board or tile images.
- Draw bounding boxes around individual tiles.
- Edit annotation metadata.
- Export cropped tile images and metadata to the backend.
Development commands:
cd glazer_admin
npm install
npm run dev
npm run buildLocation: glaze_daemon/
The daemon accepts the Glazer export at:
POST /upload
It imports cropped tile images into MariaDB and generates automatic metadata:
AutoTagsAutoKeywordsPrimaryColorColorProfileDominantColors
The richer color fields make search better for multi-color tiles. For example, a mostly blue tile with small black/red areas can still be found as blue because ColorProfile stores color percentages instead of only one averaged LAB value.
The default database is tilearchive.
Main schema:
glaze_daemon/db-schema.sql
Important tables:
testpiece: tile image, LAB values, dominant color metadata, firing info, generated tags, and generated keywords.glazetype: glaze type lookup table.surfacecondition: surface condition lookup table.tileboard: board-level records.view_testpiece_full: joined view for fuller tile data.
New uploads get automatic tags and color metadata during import.
For older rows already in the database, run:
podman compose exec glaze-daemon python backfill_auto_metadata.pyLocation: glazy_app/
Build:
cd glazy_app
dotnet build "ASTEM DB.csproj"Run:
cd glazy_app
dotnet run --project "ASTEM DB.csproj"Publish a self-contained build:
cd glazy_app
dotnet publish "ASTEM DB.csproj" -c Release -r osx-arm64 --self-contained true -o publish/osx-arm64Use the runtime identifier for your platform, such as:
osx-arm64osx-x64linux-x64win-x64
The desktop app reads DB settings from environment variables when available. If DB_HOST=tile-db, it automatically uses 127.0.0.1 for host-side desktop access.
Location: ai-search-prototype/
The Glazy desktop app has an AI Chat Search tab. Each message refines the current search context, so a follow-up like something darker after give me something brown is searched as a darker brown tile. Use the tab's reset button to start a new AI search context.
The AI tab also includes an Image button. It currently opens an image picker and stores the selected image path in the desktop app state, but visual image-to-tile ranking is intentionally not implemented here yet. The image-search team can connect their pipeline through AiSearchImagePath / SetPendingAiSearchImage(...) in glazy_app/ViewModels/MainWindowViewModel.cs.
Install dependencies:
cd ai-search-prototype
npm installRun a first-time search. This downloads the CLIP model into ai-search-prototype/model-cache if it is not already cached:
set -a
source ../.env
set +a
ALLOW_REMOTE=1 \
CLIP_MODEL=Xenova/clip-vit-base-patch16 \
node search.mjs "blue cold tile"After the model is cached, use local-only mode:
ALLOW_REMOTE=0 node search.mjs "blue cold tile"The desktop app allows the first download by default, then reuses the local cache. Set ALLOW_REMOTE=0 before launching the desktop app if you want strictly offline AI search.
AI search combines:
- CLIP text-to-image similarity.
- Dominant color/profile scoring for color words.
- Metadata scoring from automatic tags, keywords, glaze type, surface condition, firing type, and soil type.
- Visual edge scoring for constraints like
no dark edges,no brown borders, orno edges.
First-run speed is controlled by EMBEDDING_PREFILTER in .env.
EMBEDDING_PREFILTER=60embeds only the strongest initial candidates and is faster for development.EMBEDDING_PREFILTER=0embeds every missing tile image before ranking and is better for warming a full local cache.
The desktop app also uses a persistent local AI worker by default:
AI_SEARCH_WORKER=1keeps the Node/CLIP process open while the app is running, so follow-up chat searches do not reload the model.AI_SEARCH_WORKER=0disables the worker and runs one Node process per search, which is slower but useful for debugging.
AI ranking can be trained from feedback:
- Select an AI result tile in the desktop app.
- Use the AI Training buttons:
Good,Bad,Color, orEdges. - Click
Train Weightsto updateai-search-prototype/training-data/ranking-weights.json.
The feedback log is local and ignored by Git:
ai-search-prototype/training-data/feedback.jsonl
The trained weights file can be committed if the team wants to share the tuned ranking behavior.
blue cold tile
dark glossy tile
warm rustic brown tile
cream tile with red accent
dark blue sea
no dark edges
something darker
Run:
git submodule update --init --recursiveCheck:
podman compose ps
podman compose logs glaze-daemon
podman compose logs tile-dbCheck backend logs and database row count:
podman compose logs glaze-daemon
set -a
source .env
set +a
podman compose exec -T tile-db mariadb \
-u"$DB_USER" -p"$DB_PASSWORD" "$MYSQL_DATABASE" \
-e "SELECT COUNT(*) FROM testpiece;"The first search downloads the local CLIP model if needed, computes visual metrics, and caches image embeddings under:
ai-search-prototype/model-cache/
ai-search-prototype/visual-cache/
ai-search-prototype/embedding-cache/
Later searches are faster unless new tile images are added. Keep EMBEDDING_PREFILTER=60 for faster first searches, or set EMBEDDING_PREFILTER=0 when you want to warm the full cache.
- Glazer creates annotation exports.
- Glaze Daemon owns database import logic.
- MariaDB is the source of truth after import.
- Glazy reads from MariaDB.
- Local AI search ranks database tiles and returns matching IDs.
- Commit submodule changes inside
glaze_daemon/,glazer_admin/, andglazy_app/first, then commit the updated submodule pointers in this top-level repo. - Do not commit generated local files such as
.env,data/,node_modules/,ai-search-prototype/model-cache/,ai-search-prototype/embedding-cache/,ai-search-prototype/visual-cache/, orai-search-prototype/sample-images/. - Commit
ai-search-prototype/package-lock.jsonandai-search-prototype/training-data/ranking-weights.jsonwhen the team wants the same dependency versions and tuned ranking behavior.