Skip to content

Instantly share code, notes, and snippets.

@TakashiSasaki
Last active January 23, 2026 02:57
Show Gist options
  • Select an option

  • Save TakashiSasaki/2c11356b94f76a14e616fead808d6dc8 to your computer and use it in GitHub Desktop.

Select an option

Save TakashiSasaki/2c11356b94f76a14e616fead808d6dc8 to your computer and use it in GitHub Desktop.
Gemini Canvas File Generation Protocol (GCFGP-5.0)
1. Introduction
本ドキュメントは、Geminiキャンバスにおいてプレビュー可能なアーティファクトを生成するための厳格な構文、構造、および文字コード制約を定義する。
本版(5.0)では、Babel環境下での実行タイミングの確実性と、不可視文字によるパースエラー排除を主眼とする。
2. Encoding & Whitespace Sanitation (Critical)
* File Encoding: UTF-8 (BOM無し) を必須とする。
* Allowed Whitespace: ソースコード構造上の空白は以下の4文字のみ許可する。
- U+0020 (SPACE)
- U+0009 (HORIZONTAL TAB)
- U+000A (LINE FEED)
- U+000D (CARRIAGE RETURN)
* Forbidden Characters: 以下の文字は構文解析エラーの主因となるため、徹底して排除し U+0020 に置換しなければならない。
- U+00A0 (NO-BREAK SPACE) !!! STRICTLY FORBIDDEN !!!
- U+200B (ZERO WIDTH SPACE)
- U+3000 (IDEOGRAPHIC SPACE) ※文字列リテラル内を除く
3. ABNF Definition
キャンバス・ファイルブロックの構文定義は以下の通りとする。
FILE_BLOCK = BLOCK_START NEWLINE CONTENT NEWLINE BLOCK_END
BLOCK_START = BACKTICKS LANGUAGE COLON TITLE COLON FILEPATH
; Primitives
BACKTICKS = %x60 %x60 %x60 ; 三連続の重アクセント記号
LANGUAGE = 1*(ALPHA / DIGIT) ; 例: html, react
COLON = %x3A ; ":"
TITLE = 1*(VCHAR / SP) ; 空でないタイトル
FILEPATH = 1*(VCHAR) ; 空でないパス
NEWLINE = [ %x0D ] %x0A ; CRLF or LF
TERMINATOR = %x65 %x6F %x66 ; "eof"
; Content Structure
CONTENT = *OCTET ; ファイル本体データ
BLOCK_END = BACKTICKS TERMINATOR ; ""
4. Framework Specific Constraints (React/JSX)
Reactを使用する場合、ブラウザネイティブ実行のために以下の制約を適用する。
4.1 No ES Modules Syntax
* import / export 文の使用禁止。
* React, ReactDOM, Tailwind CSS 等は CDN から読み込むこと。
4.2 Global Object Destructuring
* React機能はグローバルオブジェクトから分解代入して使用すること。
(例: const { useState } = React;)
4.3 Explicit Mounting
* ReactDOM.createRoot() を使用して明示的にDOMへレンダリングする処理を含めること。
4.4 Browser-Side Transpilation
* Babel Standalone を使用し、スクリプトタグには type="text/babel" を付与すること。
5. Security & Stability Rules
プレビュー環境での安定動作を保証するため、以下の制限を適用する。
5.1 No Inline Event Handlers
* HTML属性(onclick, onload等)の使用禁止。JSX内のCamelCase属性(onClick等)は許可される。
5.2 Safe Resource Loading
* 外部リソース(CSS/JS)は HTTPS プロトコルの絶対URLのみ許可する。
* Google Fonts 等は @import ではなく <link> タグを使用すること。
5.3 Script Execution Strategy (Revised)
* React/Babel環境においては、DOMContentLoaded イベントリスナーを使用しないこと。
(理由: Babelの処理タイミングによりイベントを捕捉できないリスクがあるため)
* スクリプトは </body> タグの直前に配置し、トップレベルスコープで即時実行(マウント)すること。
* マウント対象のDOM要素(例: <div id="root">)はスクリプトより前に記述すること。
[End of Specification]
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World - Canvas Preview (Fixed)</title>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
</style>
</head>
<body class="bg-slate-50 min-h-screen flex flex-col items-center justify-center p-4">
<div class="bg-white p-10 rounded-3xl shadow-2xl border border-slate-200 max-w-sm w-full text-center transform transition hover:scale-105">
<div class="w-20 h-20 bg-indigo-100 text-indigo-600 rounded-2xl flex items-center justify-center mx-auto mb-6">
<!-- SVG Icon -->
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-10 h-10">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418" />
</svg>
</div>
<h1 id="main-heading" class="text-3xl font-black text-slate-800 mb-2">Hello World!</h1>
<p class="text-slate-500 mb-8">キャンバスでのプレビューが正常に動作しています。</p>
<!-- 修正点: onclick属性を削除し、id属性を追加 -->
<button
id="updateBtn"
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-6 rounded-xl transition-all active:scale-95 shadow-lg shadow-indigo-100"
>
メッセージを変更
</button>
<div id="status-tag" class="mt-6 inline-block px-3 py-1 bg-green-100 text-green-700 text-[10px] font-bold uppercase tracking-widest rounded-full opacity-0 transition-opacity">
JavaScript Verified
</div>
</div>
<script>
// 修正点: DOMContentLoadedを使用し、addEventListenerでイベントを登録
document.addEventListener('DOMContentLoaded', () => {
const btn = document.getElementById('updateBtn');
const heading = document.getElementById('main-heading');
const tag = document.getElementById('status-tag');
if (btn) {
btn.addEventListener('click', () => {
heading.innerText = "成功しました!";
heading.classList.add('text-indigo-600');
tag.classList.remove('opacity-0');
// ボタンの状態も変更して視覚的なフィードバックを追加
btn.innerText = "変更完了";
btn.classList.add('bg-green-600', 'hover:bg-green-700');
btn.classList.remove('bg-indigo-600', 'hover:bg-indigo-700');
});
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World - Canvas Preview</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
</style>
</head>
<body class="bg-slate-50 min-h-screen flex flex-col items-center justify-center p-4">
<div class="bg-white p-10 rounded-3xl shadow-2xl border border-slate-200 max-w-sm w-full text-center transform transition hover:scale-105">
<div class="w-20 h-20 bg-indigo-100 text-indigo-600 rounded-2xl flex items-center justify-center mx-auto mb-6">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-10 h-10">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418" />
</svg>
</div>
<h1 id="main-heading" class="text-3xl font-black text-slate-800 mb-2">Hello World!</h1>
<p class="text-slate-500 mb-8">キャンバスでのプレビューが正常に動作しています。</p>
<button
onclick="updateMessage()"
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-6 rounded-xl transition-all active:scale-95 shadow-lg shadow-indigo-100"
>
メッセージを変更
</button>
<div id="status-tag" class="mt-6 inline-block px-3 py-1 bg-green-100 text-green-700 text-[10px] font-bold uppercase tracking-widest rounded-full opacity-0 transition-opacity">
JavaScript Verified
</div>
</div>
<script>
function updateMessage() {
const heading = document.getElementById('main-heading');
const tag = document.getElementById('status-tag');
heading.innerText = "成功しました!";
heading.classList.add('text-indigo-600');
tag.classList.remove('opacity-0');
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World - Canvas Preview</title>
<!-- Tailwind CSS CDN for styling -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Helvetica Neue', Arial, 'Hiragino Kaku Gothic ProN', 'Hiragino Sans', Meiryo, sans-serif;
}
</style>
</head>
<body class="bg-gray-50 flex flex-col min-h-screen">
<!-- Header -->
<header class="bg-white shadow-sm p-6">
<div class="max-w-4xl mx-auto flex justify-between items-center">
<h1 class="text-2xl font-bold text-blue-600">Canvas Preview Test</h1>
<span class="px-3 py-1 bg-blue-100 text-blue-700 rounded-full text-sm font-medium">HTML Ver.</span>
</div>
</header>
<!-- Main Content -->
<main class="flex-grow flex items-center justify-center p-6">
<div class="bg-white p-8 rounded-2xl shadow-xl max-w-md w-full text-center">
<div class="mb-6">
<div class="w-20 h-20 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center mx-auto mb-4">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-10 h-10">
<path stroke-linecap="round" stroke-linejoin="round" d="M17.25 6.75 22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3-4.5 16.5" />
</svg>
</div>
<h2 id="greeting" class="text-3xl font-extrabold text-gray-900 mb-2">ハローワールド!</h2>
<p class="text-gray-600">キャンバス上でのHTMLレンダリングが正常に動作しています。</p>
</div>
<button
id="actionBtn"
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg transition duration-300 ease-in-out transform hover:scale-105 active:scale-95 shadow-md"
>
クリックして挨拶を変える
</button>
<div id="messageBox" class="mt-6 p-4 rounded-lg bg-green-50 text-green-700 hidden">
JavaScriptも正常に動作しています!
</div>
</div>
</main>
<!-- Footer -->
<footer class="p-6 text-center text-gray-500 text-sm">
&copy; 2026 HTML Preview System
</footer>
<script>
// DOM要素の取得
const btn = document.getElementById('actionBtn');
const greeting = document.getElementById('greeting');
const messageBox = document.getElementById('messageBox');
// クリックイベントのリスナー
btn.addEventListener('click', () => {
// テキストの変更
greeting.innerText = 'Hello, Canvas!';
greeting.classList.add('text-green-600');
// メッセージボックスの表示
messageBox.classList.remove('hidden');
// ボタンのスタイル変更
btn.innerText = '成功!';
btn.classList.replace('bg-blue-600', 'bg-green-600');
btn.classList.add('cursor-default');
btn.disabled = true;
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment