Comprehensive rebrand: ComfyUI → Hanzo Studio

- Replace all user-facing "ComfyUI" strings with "Hanzo Studio"
- Update Help menu links: Discord → discord.gg/hanzoai, GitHub → hanzoai/studio
- Replace comfy.org URLs with hanzo.ai equivalents
- Update support email to support@hanzo.ai
- Rewrite branding script to patch ALL JS bundles comprehensively
- Update default filename prefixes from ComfyUI to HanzoStudio
- Fix CI to trigger on main branch (not hanzo/main)
- Update pyproject.toml metadata (name, URLs)
This commit is contained in:
Hanzo Dev
2026-02-23 09:32:01 -08:00
parent ee087ae50e
commit 4526acbfa6
12 changed files with 139 additions and 80 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ name: Build and Deploy
on:
push:
branches: [hanzo/main]
branches: [main]
env:
REGISTRY: ghcr.io
+1 -1
View File
@@ -24,7 +24,7 @@ except ImportError as e:
------------------------------------------------------------------------
Error importing dependencies: {e}
{get_missing_requirements_message()}
This error is happening because ComfyUI now uses a local sqlite database.
This error is happening because Hanzo Studio now uses a local sqlite database.
------------------------------------------------------------------------
""".strip()
)
+2 -2
View File
@@ -27,7 +27,7 @@ def frontend_install_warning_message():
return f"""
{get_missing_requirements_message()}
This error is happening because the ComfyUI frontend is no longer shipped as part of the main repo but as a pip package instead.
This error is happening because the Hanzo Studio frontend is no longer shipped as part of the main repo but as a pip package instead.
""".strip()
def parse_version(version: str) -> tuple[int, int, int]:
@@ -87,7 +87,7 @@ ________________________________________________________________________
""".strip()
)
else:
logging.info("ComfyUI frontend version: {}".format(frontend_version_str))
logging.info("Hanzo Studio frontend version: {}".format(frontend_version_str))
except Exception as e:
logging.error(f"Failed to check frontend version: {e}")
+115 -56
View File
@@ -1,99 +1,158 @@
#!/bin/bash
# Apply Hanzo Studio branding to ComfyUI frontend
# Apply Hanzo Studio branding to ComfyUI frontend package
# This runs during Docker build after pip install to patch the pre-built frontend
set -e
STATIC_DIR=$(python3 -c "import comfyui_frontend_package, importlib.resources; print(str(importlib.resources.files(comfyui_frontend_package) / 'static'))")
BRANDING_DIR="$(dirname "$0")"
echo "Applying Hanzo Studio branding to: $STATIC_DIR"
echo "=== Hanzo Studio Branding ==="
echo "Target: $STATIC_DIR"
# 1. Replace logo SVGs
cp "$BRANDING_DIR/hanzo-logo.svg" "$STATIC_DIR/assets/images/comfy-logo-single.svg"
cp "$BRANDING_DIR/hanzo-logo.svg" "$STATIC_DIR/assets/images/comfy-logo-mono.svg"
cp "$BRANDING_DIR/hanzo-logo.svg" "$STATIC_DIR/assets/images/comfy-cloud-logo.svg"
# --- 1. Replace logo SVG files ---
echo "[1/7] Replacing logos..."
for logo_file in comfy-logo-single.svg comfy-logo-mono.svg comfy-cloud-logo.svg; do
target="$STATIC_DIR/assets/images/$logo_file"
if [ -f "$target" ]; then
cp "$BRANDING_DIR/hanzo-logo.svg" "$target"
echo " Replaced $logo_file"
fi
done
# 2. Replace favicon - convert SVG to ICO using Python
# Also replace any other logo SVGs we find
find "$STATIC_DIR" -name "*comfy*logo*" -o -name "*logo*comfy*" 2>/dev/null | while read f; do
if [[ "$f" == *.svg ]]; then
cp "$BRANDING_DIR/hanzo-logo.svg" "$f"
echo " Replaced $(basename "$f")"
fi
done
# --- 2. Replace favicon ---
echo "[2/7] Replacing favicon..."
python3 -c "
import struct, io, base64, xml.etree.ElementTree as ET
import struct
# Read the favicon SVG
with open('$BRANDING_DIR/favicon.svg', 'r') as f:
svg_content = f.read()
# Create a minimal 16x16 ICO with the H mark
# Use a simple 16x16 bitmap representation
size = 16
# Simple H pattern at 16x16
pixels = bytearray(size * size * 4) # BGRA
pixels = bytearray(size * size * 4)
# Draw the H mark (simplified geometric pattern)
for y in range(size):
for x in range(size):
idx = (y * size + x) * 4
# Background: transparent
pixels[idx] = 0 # B
pixels[idx+1] = 0 # G
pixels[idx+2] = 0 # R
pixels[idx+3] = 0 # A
# Left vertical bar (0-4, 0-15)
pixels[idx] = 0; pixels[idx+1] = 0; pixels[idx+2] = 0; pixels[idx+3] = 0
# Left vertical bar
if 1 <= x <= 4 and 1 <= y <= 14:
pixels[idx] = 255; pixels[idx+1] = 255; pixels[idx+2] = 255; pixels[idx+3] = 255
# Right vertical bar (11-14, 0-15)
# Right vertical bar
if 11 <= x <= 14 and 1 <= y <= 14:
pixels[idx] = 255; pixels[idx+1] = 255; pixels[idx+2] = 255; pixels[idx+3] = 255
# Diagonal bar (connecting, roughly y=4 to y=11, x=1 to x=14)
# Diagonal bar
if 4 <= y <= 11:
expected_x = 1 + (y - 4) * (13.0 / 7.0)
if abs(x - expected_x) <= 2:
pixels[idx] = 255; pixels[idx+1] = 255; pixels[idx+2] = 255; pixels[idx+3] = 255
# ICO format
ico = bytearray()
# ICONDIR
ico += struct.pack('<HHH', 0, 1, 1) # reserved, type=1(icon), count=1
# ICONDIRENTRY
ico += struct.pack('<HHH', 0, 1, 1)
ico += struct.pack('<BBBBHHII', size, size, 0, 0, 1, 32, len(pixels) + 40, 22)
# BITMAPINFOHEADER
ico += struct.pack('<IiiHHIIiiII', 40, size, size*2, 1, 32, 0, len(pixels), 0, 0, 0, 0)
# Pixel data (bottom-up)
for y in range(size-1, -1, -1):
ico += pixels[y*size*4:(y+1)*size*4]
with open('$STATIC_DIR/assets/favicon.ico', 'wb') as f:
f.write(ico)
print('Generated favicon.ico')
print(' Generated favicon.ico')
"
# 3. Patch index.html
sed -i 's/<title>ComfyUI<\/title>/<title>Hanzo Studio<\/title>/g' "$STATIC_DIR/index.html"
sed -i 's/Loading ComfyUI\.\.\./Loading Hanzo Studio.../g' "$STATIC_DIR/index.html"
# Also replace any other favicon files
find "$STATIC_DIR" -name "favicon*" ! -name "favicon.ico" 2>/dev/null | while read f; do
if [[ "$f" == *.svg ]]; then
cp "$BRANDING_DIR/favicon.svg" "$f"
echo " Replaced $(basename "$f")"
fi
done
# 4. Patch manifest JSON
find "$STATIC_DIR/assets" -name "manifest-*.json" -exec sed -i 's/"ComfyUI"/"Hanzo Studio"/g' {} \;
find "$STATIC_DIR/assets" -name "manifest-*.json" -exec sed -i 's/ComfyUI: AI image generation platform/Hanzo Studio: Visual AI Engine/g' {} \;
# --- 3. Patch index.html ---
echo "[3/7] Patching index.html..."
if [ -f "$STATIC_DIR/index.html" ]; then
sed -i 's/<title>ComfyUI<\/title>/<title>Hanzo Studio<\/title>/g' "$STATIC_DIR/index.html"
sed -i 's/<title>Comfy<\/title>/<title>Hanzo Studio<\/title>/g' "$STATIC_DIR/index.html"
sed -i 's/Loading ComfyUI/Loading Hanzo Studio/g' "$STATIC_DIR/index.html"
sed -i 's/Loading Comfy/Loading Hanzo Studio/g' "$STATIC_DIR/index.html"
sed -i 's/content="ComfyUI/content="Hanzo Studio/g' "$STATIC_DIR/index.html"
sed -i 's/content="Comfy/content="Hanzo Studio/g' "$STATIC_DIR/index.html"
echo " Patched index.html"
fi
# 5. Patch visible "ComfyUI" strings in JS bundles (user-facing only)
# Target the main bundle and commands for UI-visible strings
for js in "$STATIC_DIR/assets"/main-*.js "$STATIC_DIR/assets"/commands-*.js "$STATIC_DIR/assets"/settings-*.js; do
# --- 4. Patch manifest JSON files ---
echo "[4/7] Patching manifests..."
find "$STATIC_DIR" -name "manifest*.json" -exec sed -i 's/"ComfyUI"/"Hanzo Studio"/g' {} \;
find "$STATIC_DIR" -name "manifest*.json" -exec sed -i 's/"Comfy"/"Hanzo Studio"/g' {} \;
find "$STATIC_DIR" -name "manifest*.json" -exec sed -i 's/ComfyUI: AI image generation platform/Hanzo Studio: Visual AI Engine/g' {} \;
find "$STATIC_DIR" -name "manifest*.json" -exec sed -i 's/comfy\.org/hanzo.ai/g' {} \;
echo " Done"
# --- 5. Comprehensive JS bundle patching ---
echo "[5/7] Patching ALL JS bundles..."
JS_COUNT=0
for js in "$STATIC_DIR"/assets/*.js "$STATIC_DIR"/*.js; do
[ -f "$js" ] || continue
# Replace user-visible ComfyUI references
# Brand names
sed -i 's/ComfyUI/Hanzo Studio/g' "$js"
done
# 6. Patch the AboutPanel
for js in "$STATIC_DIR/assets"/AboutPanel-*.js; do
[ -f "$js" ] || continue
sed -i 's/ComfyUI/Hanzo Studio/g' "$js"
sed -i 's/comfy\.org/hanzo.ai/g' "$js"
# Organization names
sed -i 's/ComfyOrg/Hanzo AI/g' "$js"
done
sed -i 's/Comfy-Org/Hanzo AI/g' "$js"
sed -i 's/Comfy Org/Hanzo AI/g' "$js"
# 7. Patch ComfyOrgHeader
for js in "$STATIC_DIR/assets"/ComfyOrgHeader-*.js; do
[ -f "$js" ] || continue
sed -i 's/ComfyOrg/Hanzo AI/g' "$js"
# Domain replacements
sed -i 's/comfy\.org/hanzo.ai/g' "$js"
done
sed -i 's/docs\.comfy\.org/docs.hanzo.ai/g' "$js"
sed -i 's/forum\.comfy\.org/hanzo.ai\/community/g' "$js"
sed -i 's/api\.comfy\.org/api.hanzo.ai/g' "$js"
sed -i 's/platform\.comfy\.org/hanzo.ai/g' "$js"
echo "Hanzo Studio branding applied successfully"
# GitHub URLs
sed -i 's|github\.com/comfyanonymous/ComfyUI|github.com/hanzoai/studio|g' "$js"
sed -i 's|github\.com/Comfy-Org/ComfyUI|github.com/hanzoai/studio|g' "$js"
sed -i 's|github\.com/Comfy-Org|github.com/hanzoai|g' "$js"
sed -i 's|github\.com/comfyanonymous|github.com/hanzoai|g' "$js"
# Discord - replace Comfy discord with Hanzo discord
sed -i 's|discord\.gg/comfyorg|discord.gg/hanzoai|g' "$js"
sed -i 's|discord\.com/invite/comfyorg|discord.com/invite/hanzoai|g' "$js"
# Catch other Comfy discord patterns
sed -i 's|discord\.gg/[a-zA-Z0-9]*comfy[a-zA-Z0-9]*|discord.gg/hanzoai|g' "$js"
# Support email
sed -i 's/support@comfy\.org/support@hanzo.ai/g' "$js"
# Clean up any double-replacements (e.g., "Hanzo Studio Studio")
sed -i 's/Hanzo Studio Studio/Hanzo Studio/g' "$js"
sed -i 's/Hanzo Studio Manager/Hanzo Studio Manager/g' "$js"
JS_COUNT=$((JS_COUNT + 1))
done
echo " Patched $JS_COUNT JS files"
# --- 6. Patch CSS files ---
echo "[6/7] Patching CSS..."
for css in "$STATIC_DIR"/assets/*.css "$STATIC_DIR"/*.css; do
[ -f "$css" ] || continue
# Remove any ComfyUI-specific animation classes that reference the C logo
# (The spinning C logo animation)
sed -i 's/comfy\.org/hanzo.ai/g' "$css"
done
echo " Done"
# --- 7. Final verification ---
echo "[7/7] Verification..."
REMAINING=$(grep -rl "ComfyUI" "$STATIC_DIR" --include="*.html" --include="*.js" --include="*.json" 2>/dev/null | wc -l | tr -d ' ')
echo " Files still containing 'ComfyUI': $REMAINING"
if [ "$REMAINING" -gt 0 ]; then
echo " Remaining references (for review):"
grep -rl "ComfyUI" "$STATIC_DIR" --include="*.html" --include="*.js" --include="*.json" 2>/dev/null | head -5
fi
echo ""
echo "=== Hanzo Studio branding complete ==="
+1 -1
View File
@@ -225,7 +225,7 @@ parser.add_argument(
"--comfy-api-base",
type=str,
default="https://api.comfy.org",
help="Set the base URL for the ComfyUI API. (default: https://api.comfy.org)",
help="Set the base URL for the Hanzo Studio API. (default: https://api.comfy.org)",
)
database_default_path = os.path.abspath(
+1 -1
View File
@@ -514,7 +514,7 @@ def _friendly_http_message(status: int, body: Any) -> str:
if status == 402:
return "Payment Required: Please add credits to your account to use this node."
if status == 409:
return "There is a problem with your account. Please contact support@comfy.org."
return "There is a problem with your account. Please contact support@hanzo.ai."
if status == 429:
return "Rate Limit Exceeded: The server returned 429 after all retry attempts. Please wait and try again."
try:
+5 -5
View File
@@ -223,7 +223,7 @@ def cuda_malloc_warning():
if b in device_name:
cuda_malloc_warning = True
if cuda_malloc_warning:
logging.warning("\nWARNING: this card most likely does not support cuda-malloc, if you get \"CUDA error\" please run ComfyUI with: --disable-cuda-malloc\n")
logging.warning("\nWARNING: this card most likely does not support cuda-malloc, if you get \"CUDA error\" please run Hanzo Studio with: --disable-cuda-malloc\n")
def prompt_worker(q, server_instance):
@@ -363,7 +363,7 @@ def setup_database():
def start_comfyui(asyncio_loop=None):
"""
Starts the ComfyUI server using the provided asyncio event loop or creates a new one.
Starts the Hanzo Studio server using the provided asyncio event loop or creates a new one.
Returns the event loop, server instance, and a function to start the server asynchronously.
"""
if args.temp_directory:
@@ -421,14 +421,14 @@ def start_comfyui(asyncio_loop=None):
await prompt_server.setup()
await run(prompt_server, address=args.listen, port=args.port, verbose=not args.dont_print_server, call_on_start=call_on_start)
# Returning these so that other code can integrate with the ComfyUI loop and server
# Returning these so that other code can integrate with the Hanzo Studio loop and server
return asyncio_loop, prompt_server, start_all
if __name__ == "__main__":
# Running directly, just start ComfyUI.
# Running directly, just start Hanzo Studio.
logging.info("Python version: {}".format(sys.version))
logging.info("ComfyUI version: {}".format(comfyui_version.__version__))
logging.info("Hanzo Studio version: {}".format(comfyui_version.__version__))
if sys.version_info.major == 3 and sys.version_info.minor < 10:
logging.warning("WARNING: You are using a python version older than 3.10, please upgrade to a newer one. 3.12 and above is recommended.")
+1 -1
View File
@@ -1,4 +1,4 @@
"""Cache control middleware for ComfyUI server"""
"""Cache control middleware for Hanzo Studio server"""
from aiohttp import web
from typing import Callable, Awaitable
+5 -5
View File
@@ -484,7 +484,7 @@ class SaveLatent:
@classmethod
def INPUT_TYPES(s):
return {"required": { "samples": ("LATENT", ),
"filename_prefix": ("STRING", {"default": "latents/ComfyUI"})},
"filename_prefix": ("STRING", {"default": "latents/HanzoStudio"})},
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
}
RETURN_TYPES = ()
@@ -494,7 +494,7 @@ class SaveLatent:
CATEGORY = "_for_testing"
def save(self, samples, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None):
def save(self, samples, filename_prefix="HanzoStudio", prompt=None, extra_pnginfo=None):
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir)
# support save metadata for latent sharing
@@ -1638,7 +1638,7 @@ class SaveImage:
return {
"required": {
"images": ("IMAGE", {"tooltip": "The images to save."}),
"filename_prefix": ("STRING", {"default": "ComfyUI", "tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes."})
"filename_prefix": ("STRING", {"default": "HanzoStudio", "tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes."})
},
"hidden": {
"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"
@@ -1652,10 +1652,10 @@ class SaveImage:
CATEGORY = "image"
ESSENTIALS_CATEGORY = "Basics"
DESCRIPTION = "Saves the input images to your ComfyUI output directory."
DESCRIPTION = "Saves the input images to your Hanzo Studio output directory."
SEARCH_ALIASES = ["save", "save image", "export image", "output image", "write image", "download"]
def save_images(self, images, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None):
def save_images(self, images, filename_prefix="HanzoStudio", prompt=None, extra_pnginfo=None):
filename_prefix += self.prefix_append
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0])
results = list()
+4 -4
View File
@@ -1,14 +1,14 @@
[project]
name = "ComfyUI"
name = "hanzo-studio"
version = "0.14.1"
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.10"
[project.urls]
homepage = "https://www.comfy.org/"
repository = "https://github.com/comfyanonymous/ComfyUI"
documentation = "https://docs.comfy.org/"
homepage = "https://hanzo.ai"
repository = "https://github.com/hanzoai/studio"
documentation = "https://docs.hanzo.ai"
[tool.ruff]
lint.select = [
+2 -2
View File
@@ -1,7 +1,7 @@
import json
from urllib import request
#This is the ComfyUI api prompt format.
#This is the Hanzo Studio api prompt format.
#If you want it for a specific workflow you can "File -> Export (API)" in the interface.
@@ -85,7 +85,7 @@ prompt_text = """
"9": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "ComfyUI",
"filename_prefix": "HanzoStudio",
"images": [
"8",
0
+1 -1
View File
@@ -135,7 +135,7 @@ prompt_text = """
"9": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "ComfyUI",
"filename_prefix": "HanzoStudio",
"images": [
"8",
0