Chuyển đến nội dung chính

レッスン 4: Design Studio & Canvas Editor — Web エディター、テンプレート エンジン & アセット ライブラリ

Design Studio の Web ベースのアーキテクチャ、Canvas/WebGL レンダリング、レイヤー システム、テンプレート エンジン、アセット ライブラリ、フォント管理、共同編集、エクスポート パイプライン (PNG/SVG/PDF)。

🏗️ アーキテクチャ — レッスン 4 レッスン 4: デザイン スタジオとキャンバス エディター — Web エディター、テンプレート エンジン、アセット ライブラリ

ファッション デザインとプリント オン デマンド システム アーキテクチャ — ドメイン分析から生産まで

パート 2: AI を活用したデザイン スタジオ

xdev.asia

1. デザインスタジオのアーキテクチャ

デザインスタジオは コアクリエイティブツール POD プラットフォームの利用 — デザイナーは Web ブラウザーで直接デザインを作成、編集、エクスポートできます。

┌──────────────────────────────────────────────────────────┐
│                    Design Studio UI                       │
│  ┌──────┐ ┌──────────────────────────────┐ ┌──────────┐  │
│  │Panels│ │       Canvas Area           │ │Properties│  │
│  │      │ │  ┌────────────────────────┐  │ │  Panel   │  │
│  │Layers│ │  │                        │  │ │          │  │
│  │Assets│ │  │   [Canvas Renderer]    │  │ │  Fill    │  │
│  │Text  │ │  │   WebGL / Canvas 2D    │  │ │  Stroke  │  │
│  │AI Gen│ │  │                        │  │ │  Font    │  │
│  │      │ │  └────────────────────────┘  │ │  Effects │  │
│  └──────┘ └──────────────────────────────┘ └──────────┘  │
│  ┌──────────────────────────────────────────────────────┐ │
│  │  Toolbar: Select | Text | Shape | Image | AI | Undo │ │
│  └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘

2. キャンバス レンダラーのアーキテクチャ

// Canvas Engine — Fabric.js based architecture
interface CanvasEngine {
  // Core rendering
  renderer: WebGLRenderer | Canvas2DRenderer;
  scene: SceneGraph;
  viewport: Viewport;
  
  // Object management
  objects: DesignObject[];
  selectedObjects: DesignObject[];
  
  // History
  undoStack: CanvasState[];
  redoStack: CanvasState[];
}

type DesignObject = 
  | TextObject 
  | ImageObject 
  | ShapeObject 
  | GroupObject 
  | ClipPathObject;

interface TextObject {
  type: 'text';
  id: string;
  content: string;
  fontFamily: string;
  fontSize: number;
  fill: string | Gradient | Pattern;
  position: { x: number; y: number };
  rotation: number;
  opacity: number;
  effects: TextEffect[];
  // Print-specific
  outlineForPrint: boolean; // Convert text → paths for RIP
}

interface ImageObject {
  type: 'image';
  id: string;
  src: string;          // Original hi-res URL
  thumbnail: string;    // Preview thumbnail
  position: { x: number; y: number };
  size: { width: number; height: number };
  cropRect?: CropRect;
  filters: ImageFilter[];
  // Print-specific
  dpi: number;          // >= 300 for print
  colorSpace: 'rgb' | 'cmyk';
}

レンダリングパイプライン

User Action → Command → Scene Graph Update → Render Queue
                                                    │
                                              ┌─────▼──────┐
                                              │ Dirty Rect  │
                                              │ Detection   │
                                              └─────┬──────┘
                                                    │
                                      ┌─────────────┼──────────────┐
                                      ▼             ▼              ▼
                               ┌──────────┐  ┌──────────┐  ┌──────────┐
                               │Background│  │ Objects  │  │ Overlay  │
                               │  Layer   │  │  Layer   │  │  Layer   │
                               │(template)│  │(designs) │  │(guides,  │
                               │          │  │          │  │ handles) │
                               └──────────┘  └──────────┘  └──────────┘
                                      │             │              │
                                      └─────────────┼──────────────┘
                                                    ▼
                                              Composited Frame
                                              → Display

3. レイヤーシステム

interface LayerManager {
  layers: Layer[];
  
  addLayer(object: DesignObject): Layer;
  removeLayer(layerId: string): void;
  reorderLayer(layerId: string, newIndex: number): void;
  groupLayers(layerIds: string[]): GroupLayer;
  
  // Visibility & locking
  toggleVisibility(layerId: string): void;
  toggleLock(layerId: string): void;
  
  // Blending
  setBlendMode(layerId: string, mode: BlendMode): void;
  setOpacity(layerId: string, opacity: number): void;
}

type BlendMode = 
  | 'normal' | 'multiply' | 'screen' | 'overlay' 
  | 'darken' | 'lighten' | 'color-dodge' | 'color-burn';

interface Layer {
  id: string;
  name: string;
  object: DesignObject;
  visible: boolean;
  locked: boolean;
  blendMode: BlendMode;
  opacity: number;
  zIndex: number;
}

4. テンプレートエンジン

interface DesignTemplate {
  id: string;
  name: string;
  category: 'tshirt' | 'hoodie' | 'mug' | 'poster' | 'phone_case';
  
  // Canvas dimensions
  canvas: {
    width: number;   // pixels at 300 DPI
    height: number;
    dpi: number;
  };
  
  // Print area definition
  printArea: {
    x: number;
    y: number;
    width: number;
    height: number;
    safeZone: number;  // margin from edge
  };
  
  // Pre-placed elements (editable placeholders)
  placeholders: Array<{
    id: string;
    type: 'text' | 'image' | 'shape';
    label: string;         // "Your text here"
    position: Position;
    style: Partial;
    editable: boolean;
    required: boolean;
  }>;
  
  // Background/mockup preview
  previewMockup: string;  // Product image with design area overlay
}

// Template cho T-shirt Front
const tshirtFrontTemplate: DesignTemplate = {
  id: 'tmpl-tshirt-front-standard',
  name: 'T-Shirt Front — Standard',
  category: 'tshirt',
  canvas: { width: 4500, height: 5400, dpi: 300 },  // 15" x 18" at 300 DPI
  printArea: { x: 150, y: 150, width: 4200, height: 5100, safeZone: 75 },
  placeholders: [
    {
      id: 'main-text',
      type: 'text',
      label: 'Your Design Here',
      position: { x: 2250, y: 2700 },
      style: { fontSize: 200, fontFamily: 'Inter', fill: '#ffffff' },
      editable: true,
      required: false,
    }
  ],
  previewMockup: '/mockups/tshirt-front-preview.png',
};

5. アセットライブラリとフォント管理

interface AssetLibrary {
  // Categories
  categories: AssetCategory[];
  
  // Search & filter
  search(query: string, filters: AssetFilter): Promise<Asset[]>;
  
  // User uploads
  uploadAsset(file: File, metadata: AssetMetadata): Promise<Asset>;
}

interface Asset {
  id: string;
  type: 'clipart' | 'icon' | 'photo' | 'pattern' | 'font' | 'ai_generated';
  name: string;
  thumbnail: string;
  fullUrl: string;
  tags: string[];
  license: 'free' | 'premium' | 'user_uploaded';
  
  // Technical
  format: 'svg' | 'png' | 'webp';
  dimensions?: { width: number; height: number };
  fileSize: number;
  transparent: boolean;
}

// Font loading strategy
interface FontManager {
  // System fonts pre-loaded
  systemFonts: FontFace[];
  
  // On-demand loading
  loadFont(fontFamily: string): Promise<FontFace>;
  
  // Font subsetting for export (only glyphs used)
  subsetFont(fontFamily: string, text: string): Promise<ArrayBuffer>;
  
  // Convert text to paths (for RIP compatibility)
  textToPath(textObject: TextObject): Promise<SVGPathElement>;
}

6. パイプラインのエクスポート

Canvas State
     │
     ├── Preview Export (fast, low-res)
     │   └── WebP, 72 DPI, max 1200px → CDN
     │
     ├── Mockup Export (medium)
     │   └── PNG, 150 DPI, product composite → CDN
     │
     └── Print Export (high-res, production)
         │
         ├── Text → Paths (outline fonts)
         ├── Images → full resolution
         ├── Color space conversion (RGB → CMYK if needed)
         ├── Add bleed & trim marks
         ├── Flatten layers
         └── Output:
             ├── PNG (300 DPI, transparent background) — for DTG/DTF
             ├── PDF/X-4 (CMYK, ICC profile) — for offset/sublimation
             └── SVG (vector) — for vinyl cut/screen print
interface ExportService {
  exportForPreview(canvasState: CanvasState): Promise<string> ;  // WebP URL
  exportForMockup(canvasState: CanvasState, template: MockupTemplate): Promise<string>;
  exportForPrint(canvasState: CanvasState, printSpec: PrintSpec): Promise<PrintFile>;
}

interface PrintSpec {
  format: 'png' | 'pdf' | 'svg';
  dpi: number;           // 300 for most, 600 for fine art
  colorSpace: 'rgb' | 'cmyk';
  iccProfile?: string;   // 'USWebCoatedSWOP' | 'sRGB'
  bleed: number;         // mm
  includeTriMarks: boolean;
  flattenLayers: boolean;
  textToOutlines: boolean;
}

interface PrintFile {
  url: string;
  format: string;
  width: number;
  height: number;
  dpi: number;
  colorSpace: string;
  fileSizeBytes: number;
  checksum: string;     // SHA-256 for integrity
}

7. 元に戻す/やり直しと状態管理

// Command pattern for undo/redo
interface CanvasCommand {
  execute(): void;
  undo(): void;
  description: string;
}

class MoveObjectCommand implements CanvasCommand {
  constructor(
    private object: DesignObject,
    private from: Position,
    private to: Position,
  ) {}

  execute() { this.object.position = this.to; }
  undo() { this.object.position = this.from; }
  description = 'Move object';
}

class HistoryManager {
  private undoStack: CanvasCommand[] = [];
  private redoStack: CanvasCommand[] = [];
  private maxHistory = 50;

  execute(command: CanvasCommand) {
    command.execute();
    this.undoStack.push(command);
    this.redoStack = []; // Clear redo on new action
    if (this.undoStack.length > this.maxHistory) {
      this.undoStack.shift();
    }
  }

  undo() {
    const command = this.undoStack.pop();
    if (command) {
      command.undo();
      this.redoStack.push(command);
    }
  }

  redo() {
    const command = this.redoStack.pop();
    if (command) {
      command.execute();
      this.undoStack.push(command);
    }
  }
}

8. まとめ

  • キャンバスエンジン — WebGL/Canvas 2D レンダリング、dirty-rect 最適化、60fps ターゲット

  • レイヤーシステム — Z オーダー、ブレンド モード、グループ化、可視性/ロック

  • テンプレートエンジン — 印刷領域、プレースホルダー、セーフゾーンを備えた製品固有のテンプレート

  • アセットライブラリ — クリップアート、アイコン、パターン、フォント、AI 生成アセット

  • エクスポートパイプライン — プレビュー (72 DPI WebP) → モックアップ (150 DPI PNG) → 印刷 (300 DPI 印刷対応)

  • 元に戻す/やり直す — コマンドパターン、50ステップ履歴