AI workflows, character systems, and ComfyUI experiments
// A-LINE · LAB

Screenshots

// A-LINE · IN-ENGINE
// 01 · character customization

Character Customization AI Repaint

A Unity face-creation pipeline. Player draws on the in-game canvas, ComfyUI runs a custom face_blindbox LoRA plus ControlNet Scribble, and the texture comes back in seconds.

  • ComfyUI
  • kohya_ss
  • SDXL
  • ControlNet Scribble
  • IPAdapter
  • Unity HTTP bridge
LoRA training set — 12 hand-curated references
LoRA ref 2
LoRA ref 3
LoRA ref 4
LoRA ref 5
LoRA ref 6
LoRA ref 7
LoRA ref 8
LoRA ref 9
LoRA ref 10
LoRA ref 11
LoRA ref 12
LoRA ref 14
Pipeline overview + ComfyUI workflow
Pipeline flow
ComfyUI workflow
Before the LoRA — 50 prompt-only iterations
Early iteration #1
Early iteration #2
Early iteration #3
Early iteration #4
Early iteration #5
Early iteration #6
Early iteration #7
Early iteration #8
Early iteration #9
Early iteration #10
Early iteration #11
Early iteration #12
Early iteration #13
Early iteration #14
Early iteration #15
Early iteration #16
Early iteration #17
Early iteration #18
Early iteration #19
Early iteration #20
Early iteration #21
Early iteration #22
Early iteration #23
Early iteration #24
Early iteration #25
Early iteration #26
Early iteration #27
Early iteration #28
Early iteration #29
Early iteration #30
Early iteration #31
Early iteration #32
Early iteration #33
Early iteration #34
Early iteration #35
Early iteration #36
Early iteration #37
Early iteration #38
Early iteration #39
Early iteration #40
Early iteration #41
Early iteration #42
Early iteration #43
Early iteration #44
Early iteration #45
Early iteration #46
Early iteration #47
Early iteration #48
Early iteration #49
Early iteration #50
After the LoRA — 64 player-generated faces
Playtest face 305
Playtest face 306
Playtest face 307
Playtest face 308
Playtest face 309
Playtest face 310
Playtest face 311
Playtest face 312
Playtest face 313
Playtest face 314
Playtest face 315
Playtest face 316
Playtest face 317
Playtest face 318
Playtest face 319
Playtest face 320
Playtest face 321
Playtest face 322
Playtest face 323
Playtest face 324
Playtest face 325
Playtest face 326
Playtest face 327
Playtest face 328
Playtest face 329
Playtest face 330
Playtest face 331
Playtest face 332
Playtest face 333
Playtest face 334
Playtest face 335
Playtest face 336
Playtest face 337
Playtest face 338
Playtest face 339
Playtest face 340
Playtest face 341
Playtest face 342
Playtest face 343
Playtest face 344
Playtest face 345
Playtest face 346
Playtest face 347
Playtest face 348
Playtest face 349
Playtest face 350
Playtest face 351
Playtest face 352
Playtest face 353
Playtest face 354
Playtest face 355
Playtest face 356
Playtest face 357
Playtest face 358
Playtest face 359
Playtest face 360
Playtest face 361
Playtest face 362
Playtest face 363
Playtest face 364
Playtest face 365
Playtest face 366
Playtest face 367
Playtest face 368
Expression generator — V4 to V7 iteration wall
V4 smile
V4 laugh
V4 angry
V4 sad
V4 surprised
V5 smile
V5 laugh
V5 angry
V5 sad
V5 surprised
V6 happy
V6 angry
V6 sad
V6 shocked
V6b happy
V6b angry
V6b sad
V6b shocked
Happy A
Happy B
Happy C
Happy D
Final happy 350
Final happy 355
Final happy 359
Final2 happy 350
Final2 happy 355
Final2 happy 359
V7 happy
V7 angry
V7 sad
V7 shocked
Final expression set — base / happy / angry / sad / shocked
Base
Happy
Angry
Sad
Shocked
UV-mapped to 3D characters
Chiikawa
Angel
CAITLYN
Xiruo
Character preview
Character 2
Test preview
Playtest 000
Character animation — walking demo
// 02 · ai-generated ui

AI UI Workflow

Feed AI a stack of references, generate concept sheets and design principles, then curate and assemble the pieces in Figma into the final Unity interface.

  • Scenario
  • AI references
  • Design principles
  • Figma
  • Unity URP
  • transparent PNG
Step 01 // References I fed in
Initial direction
Initial direction
Reference board
Reference board
Step 02 // AI-generated concept + component library
AI UI concept 01
AI UI concept 02
AI UI concept 03
AI UI concept 04
Step 03 // AI-generated design principles
Design system sheet A
Design system sheet B
Manual assembly — final Figma panels built in Unity
Face panel
Face panel
Hair panel
Hair panel
Personality panel
Personality panel
Final result
Final UI result
// 03 · ai-assisted 3d

AI Helps 3D Workflow

Two paths feeding the 3D pipeline: image-to-3D plus DCC validation, and manual modeling with AI texture passes before Unity integration.

  • GPT-4
  • Image-to-3D
  • Blender
  • UV unwrap
  • AI textures
  • Unity URP
  • asset check
Module 01 · Image-to-3D + DCC export
Image-to-3D — complete concept to AI-split modeling sheet
Complete AI concept
AI-split parts
DCC asset check tool — custom Blender add-on
Asset health check
Unity export topology
Asset check tool — source code
asset_health_check.pypython
bl_info = {
    "name": "Asset Health Check",
    "author": "Yvaine",
    "version": (0, 5, 0),
    "blender": (4, 0, 0),
    "location": "View3D > Sidebar (N) > Asset Check",
    "description": "Game-art mesh audit + one-click fixes.",
    "category": "Object",
}

import bpy
import bmesh
from mathutils import Vector
from bpy.props import BoolProperty, EnumProperty, FloatProperty, IntProperty
from bpy.props import PointerProperty, StringProperty
from bpy.types import Operator, Panel, PropertyGroup


def _iter_target_meshes(context):
    for obj in context.selected_objects:
        if obj.type == 'MESH' and obj.data is not None:
            yield obj


def _audit_mesh(obj):
    me = obj.data
    bm = bmesh.new()
    bm.from_mesh(me)
    bm.normal_update()

    non_manifold_edges = sum(1 for e in bm.edges if not e.is_manifold)
    boundary_edges = sum(1 for e in bm.edges if e.is_boundary)
    loose_verts = sum(1 for v in bm.verts if not v.link_edges)
    loose_edges = sum(1 for e in bm.edges if not e.link_faces)
    zero_area_faces = sum(1 for f in bm.faces if f.calc_area() < 1e-9)
    ngons = sum(1 for f in bm.faces if len(f.verts) > 4)
    tris = sum(1 for f in bm.faces if len(f.verts) == 3)

    flipped_estimate = 0
    for f in bm.faces:
        neigh = [nf for e in f.edges for nf in e.link_faces if nf is not f]
        if not neigh:
            continue
        avg = neigh[0].normal.copy() * 0
        for nf in neigh:
            avg = avg + nf.normal
        avg /= len(neigh)
        if f.normal.dot(avg) < -0.5:
            flipped_estimate += 1

    bm.free()

    s = obj.scale
    scale_off = abs(s.x - 1) > 1e-4 or abs(s.y - 1) > 1e-4 or abs(s.z - 1) > 1e-4

    return {
        "name": obj.name,
        "verts": len(me.vertices),
        "tris": tris,
        "faces": len(me.polygons),
        "non_manifold_edges": non_manifold_edges,
        "boundary_edges": boundary_edges,
        "loose_verts": loose_verts,
        "loose_edges": loose_edges,
        "zero_area_faces": zero_area_faces,
        "ngons": ngons,
        "flipped_estimate": flipped_estimate,
        "has_custom_normals": me.has_custom_normals,
        "scale_off": scale_off,
        "scale": (s.x, s.y, s.z),
        "materials": len(obj.material_slots),
    }


def _format_report(rows):
    headers = ["name", "verts", "tris", "ngons", "nm_e", "loose_v",
               "loose_e", "zero_area", "flip?", "scale!=1", "mats"]
    lines = [" | ".join(headers)]
    for r in rows:
        lines.append(" | ".join(str(x) for x in [
            r["name"], r["verts"], r["tris"], r["ngons"],
            r["non_manifold_edges"], r["loose_verts"], r["loose_edges"],
            r["zero_area_faces"], r["flipped_estimate"],
            "Y" if r["scale_off"] else "-",
            r["materials"],
        ]))
    return "\n".join(lines)


class ASSETCHK_OT_Check(Operator):
    bl_idname = "assetchk.check"
    bl_label = "Check Selected"
    bl_description = "Audit selected meshes; results shown in panel and console"

    def execute(self, context):
        targets = list(_iter_target_meshes(context))
        if not targets:
            self.report({'WARNING'}, "No mesh objects selected")
            return {'CANCELLED'}

        rows = [_audit_mesh(o) for o in targets]
        report = _format_report(rows)
        context.scene.assetchk.last_report = report
        print("\n[Asset Health Check]\n" + report + "\n")

        problems = sum(
            r["non_manifold_edges"] + r["loose_verts"] + r["loose_edges"]
            + r["zero_area_faces"] + r["flipped_estimate"] + (1 if r["scale_off"] else 0)
            for r in rows
        )
        if problems == 0:
            self.report({'INFO'}, f"OK — {len(rows)} mesh(es), no issues found")
        else:
            self.report({'WARNING'}, f"{len(rows)} mesh(es), {problems} potential issue(s)")
        return {'FINISHED'}


class ASSETCHK_OT_FixFaceOrientation(Operator):
    bl_idname = "assetchk.fix_face_orientation"
    bl_label = "Fix Flipped Normals"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        targets = list(_iter_target_meshes(context))
        if not targets:
            self.report({'WARNING'}, "No mesh objects selected")
            return {'CANCELLED'}

        prev_active = context.view_layer.objects.active
        if context.mode != 'OBJECT':
            bpy.ops.object.mode_set(mode='OBJECT')

        for obj in targets:
            context.view_layer.objects.active = obj
            obj.select_set(True)
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.mesh.normals_make_consistent(inside=False)
            bpy.ops.object.mode_set(mode='OBJECT')

        if prev_active is not None:
            context.view_layer.objects.active = prev_active
        self.report({'INFO'}, f"Recalculated normals on {len(targets)} mesh(es)")
        return {'FINISHED'}


class ASSETCHK_OT_ExportUnity(Operator):
    bl_idname = "assetchk.export_unity"
    bl_label = "Export to Unity"
    bl_description = "FBX export with Unity-friendly Y-up / -Z forward settings."

    def execute(self, context):
        # Full add-on continues with naming checks, transform fixes,
        # one-file-per-object FBX export, UI panels, registration,
        # and the last report display in the Blender sidebar.
        return {'FINISHED'}
Mesh inspection in Blender
Blender viewport cleanup
Final — in Unity URP
Unity URP lit scene
Module 02 · Modeling + textures
Preview — manual modeling + AI textures
Manual modeling preview
Unity mesh + UV to AI-generated label texture
Unity mesh
Unity mesh
AI texture
AI texture
// 04 · marketing & ip

Posters · stickers · merch

Blender pose to AI background to final poster, then extended into stickers, merch directions, and an in-game async photo feature.

  • Blender
  • Gemini
  • ComfyUI
  • IPAdapter
  • INSPYRENET
  • 4x UltraSharp
  • scene LoRA
Module 01 · Key visual iteration
v1 — initial key visuals
Tape bond
Connection tape
v2 — concepts that sell the game feel
Theme park
Circle up
Board game
Campfire
v3 — final cast group photo + A3 posters
A3 poster 1
A3 poster 2
Final cast group
Module 02 · Poster pipeline + stickers
Yarn theme — Blender · AI background · final poster
Blender yarn
AI background rose
Final poster rose
Cassette theme — Blender · AI background · final poster
Blender cassette
AI background cassette
Final poster cassette
Check-in photos — Unity pose to AI transparent pose
3D reference
3D reference
AI transparent pose
AI transparent pose
Final — composited with custom A-LINE frame
Pose 01
Pose 02
Pose 03
Pose 04
Pose 05
Pose 06
Sticker packs — hand-drawn base, AI restyled per character
Handdrawn original
AI blue
AI white
AI sticker 04
AI sticker 05
AI sticker 06
A-LINE · 2026 · Yuchen Hu

Create a free website with Framer, the website builder loved by startups, designers and agencies.