Skip to content

UIの作成

webTaleKitでは、HTML・CSS・JavaScriptを使って自由にUIを作成できます。

UIファイルの構成

各シーンのUIは、3つのファイルで構成されます:

src/screen/
├── default.html    # UIの構造(HTML)
├── default.css     # UIのスタイル(CSS)
└── default.js      # UIの動作(JavaScript)

デフォルトUIの構造

HTML (default.html)

html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="default.css">
</head>
<body>
  <!-- ゲームコンテナ -->
  <div id="game-container">
    <!-- キャンバスレイヤー(背景・キャラクター) -->
    <canvas id="game-canvas"></canvas>

    <!-- メッセージウィンドウ -->
    <div id="message-window">
      <div id="character-name"></div>
      <div id="message-text"></div>
      <div id="next-indicator">▼</div>
    </div>

    <!-- 選択肢コンテナ -->
    <div id="choice-container"></div>

    <!-- UIコントロール -->
    <div id="ui-controls">
      <button id="menu-button">Menu</button>
      <button id="skip-button">Skip</button>
      <button id="auto-button">Auto</button>
    </div>
  </div>

  <script src="default.js"></script>
</body>
</html>

CSS (default.css)

css
/* ゲームコンテナ */
#game-container {
  position: relative;
  width: 1280px;
  height: 720px;
  margin: 0 auto;
  overflow: hidden;
  background-color: #000;
}

/* キャンバス */
#game-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
}

/* メッセージウィンドウ */
#message-window {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  width: 90%;
  max-width: 1100px;
  background: rgba(0, 0, 0, 0.8);
  border: 2px solid #333;
  border-radius: 10px;
  padding: 20px;
  z-index: 10;
}

/* キャラクター名 */
#character-name {
  font-size: 20px;
  font-weight: bold;
  color: #ffcc00;
  margin-bottom: 10px;
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
}

/* メッセージテキスト */
#message-text {
  font-size: 18px;
  line-height: 1.8;
  color: #ffffff;
  min-height: 80px;
}

/* 次へ進むインジケーター */
#next-indicator {
  position: absolute;
  bottom: 10px;
  right: 20px;
  font-size: 24px;
  color: #ffcc00;
  animation: blink 1s infinite;
}

@keyframes blink {
  0%, 50% { opacity: 1; }
  51%, 100% { opacity: 0; }
}

/* 選択肢コンテナ */
#choice-container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 80%;
  max-width: 600px;
  z-index: 20;
  display: none;
}

.choice-item {
  background: linear-gradient(to bottom, #4a4a4a, #2a2a2a);
  border: 2px solid #666;
  border-radius: 8px;
  padding: 15px 20px;
  margin: 10px 0;
  font-size: 18px;
  color: #fff;
  cursor: pointer;
  transition: all 0.3s;
  text-align: center;
}

.choice-item:hover {
  background: linear-gradient(to bottom, #5a5a5a, #3a3a3a);
  border-color: #ffcc00;
  transform: scale(1.05);
}

.choice-item:active {
  background: linear-gradient(to bottom, #3a3a3a, #1a1a1a);
}

/* UIコントロール */
#ui-controls {
  position: absolute;
  top: 20px;
  right: 20px;
  z-index: 15;
}

#ui-controls button {
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid #666;
  color: #fff;
  padding: 10px 15px;
  margin-left: 10px;
  border-radius: 5px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.3s;
}

#ui-controls button:hover {
  background: rgba(50, 50, 50, 0.8);
  border-color: #ffcc00;
}

JavaScript (default.js)

javascript
// UIの初期化
document.addEventListener('DOMContentLoaded', () => {
  const messageWindow = document.getElementById('message-window');
  const characterName = document.getElementById('character-name');
  const messageText = document.getElementById('message-text');
  const nextIndicator = document.getElementById('next-indicator');
  const choiceContainer = document.getElementById('choice-container');

  // メッセージ表示関数
  window.showMessage = (name, text) => {
    if (name) {
      characterName.textContent = name;
      characterName.style.display = 'block';
    } else {
      characterName.style.display = 'none';
    }
    messageText.textContent = text;
    nextIndicator.style.display = 'block';
  };

  // 選択肢表示関数
  window.showChoices = (choices) => {
    choiceContainer.innerHTML = '';
    choiceContainer.style.display = 'block';
    messageWindow.style.display = 'none';

    choices.forEach((choice, index) => {
      const button = document.createElement('div');
      button.className = 'choice-item';
      button.textContent = choice.label;
      button.addEventListener('click', () => {
        choice.onSelect();
        choiceContainer.style.display = 'none';
        messageWindow.style.display = 'block';
      });
      choiceContainer.appendChild(button);
    });
  };

  // メニューボタン
  document.getElementById('menu-button').addEventListener('click', () => {
    // メニュー表示処理
    console.log('Menu clicked');
  });

  // スキップボタン
  document.getElementById('skip-button').addEventListener('click', () => {
    // スキップ処理
    console.log('Skip clicked');
  });

  // オートボタン
  document.getElementById('auto-button').addEventListener('click', () => {
    // オート再生処理
    console.log('Auto clicked');
  });
});

カスタムUIの作成

1. 新しいUIファイルを作成

カスタムUIを作成する場合は、新しいファイルセットを作成します:

src/screen/
├── custom.html
├── custom.css
└── custom.js

2. シーンで使用するUIを指定

html
<script>
const sceneConfig = {
  template: 'custom',  // customテンプレートを使用
  background: 'room.jpg'
}
</script>

実用的なUIの例

ビジュアルノベル風UI

html
<!-- visual-novel.html -->
<div id="game-container">
  <canvas id="game-canvas"></canvas>

  <div id="vn-message-box">
    <div class="name-plate">
      <span id="vn-character-name"></span>
    </div>
    <div id="vn-message-text"></div>
  </div>

  <div id="vn-choices"></div>
</div>
css
/* visual-novel.css */
#vn-message-box {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.9), rgba(0, 0, 0, 0.7));
  padding: 30px;
  min-height: 150px;
}

.name-plate {
  position: absolute;
  top: -30px;
  left: 30px;
  background: #2c3e50;
  color: #ecf0f1;
  padding: 8px 20px;
  border-radius: 8px 8px 0 0;
  font-weight: bold;
}

ADV風UI

html
<!-- adv.html -->
<div id="game-container">
  <canvas id="game-canvas"></canvas>

  <div id="adv-text-box">
    <div id="adv-text"></div>
    <div class="history-button">履歴</div>
  </div>
</div>
css
/* adv.css */
#adv-text-box {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 90%;
  background: rgba(255, 255, 255, 0.95);
  border: 3px solid #333;
  padding: 40px;
  font-size: 20px;
  line-height: 2;
  color: #333;
}

エンジンAPIとの連携

メッセージの表示

javascript
// エンジンからメッセージを受け取る
engine.on('message', (data) => {
  showMessage(data.name, data.text);
});

選択肢の処理

javascript
// エンジンから選択肢を受け取る
engine.on('choice', (data) => {
  showChoices(data.items);
});

カスタムイベント

javascript
// 独自のUIイベントを定義
document.getElementById('save-button').addEventListener('click', () => {
  engine.save(1); // スロット1にセーブ
});

document.getElementById('load-button').addEventListener('click', () => {
  engine.load(1); // スロット1からロード
});

レスポンシブ対応

自動スケーリング

css
#game-container {
  width: 1280px;
  height: 720px;
  transform-origin: top left;
}

@media (max-width: 1280px) {
  #game-container {
    transform: scale(0.8);
  }
}

@media (max-width: 1024px) {
  #game-container {
    transform: scale(0.6);
  }
}

モバイル対応

css
@media (max-width: 768px) {
  #message-window {
    width: 95%;
    padding: 15px;
  }

  #message-text {
    font-size: 16px;
  }

  #ui-controls {
    bottom: 180px;
    right: 10px;
  }

  #ui-controls button {
    padding: 8px 12px;
    font-size: 12px;
  }
}

ベストプラクティス

1. 一貫性のあるデザイン

同じゲーム内では、統一されたデザイン言語を使用しましょう。

2. アクセシビリティ

  • 十分なコントラスト比を確保
  • フォントサイズは読みやすいサイズに
  • ボタンは十分な大きさとクリック領域を確保

3. パフォーマンス

  • 不要なアニメーションは避ける
  • 画像は適切なサイズに最適化
  • CSSのtransitionを活用

4. テスト

複数のブラウザとデバイスでテストしましょう:

  • Chrome
  • Firefox
  • Edge
  • モバイルブラウザ

次のステップ

Released under the MIT License.