TypeForge は、 ブラウザだけで文字を 3D に押し出して PNG ダウンロードできる無料の 3D テキスト ジェネレーター。 Three.js + WebGL でリアルタイム描画し、 5 種の材質 (matte / metal / chrome / neon / glass) を切り替え、 ドラッグで回転して PNG 1080×1080 で取り出す。 全部、 サーバーは経由しない。 ラボ 19本目、 ジェネレーター ジャンル 1本目。
#なぜこの形にしたか — 作るジャンルを広げる
直近 5本は (wiki-orbit: データ可視化 / fate-num: 占い / roof-fund: 計算ツール / coin-stack: 計算ツール / pitch-flip: 端末内で動く機械学習)。 3 本続いてはいないが、 作ろうと決めていた 8 ジャンルのうち ジェネレーター はラボにゼロ。 今のうちに 「ジェネレーター系もできる」 を布石として置く。
候補を比較した:
- 配色パレットジェネレーター (utility 高、 wow 中)
- AI 短歌ジェネレーター (純 JS だと品質弱い)
- SVG モノグラムロゴ (utility 中、 wow 中)
- 3D テキスト ジェネレーター (採用)
選んだ理由:
- 野心スタックとして Three.js をラボ初投入できる (まだラボに 3D / WebGL は無い)
- 既存大手 (3DText.io / Cooltext) はサーバー側生成 + 透かし or 課金。 + 透かしなしで明確に差別化
- SNS アイコン / バナー / プレゼン素材 需要は安定して強く、 「3D ロゴ ジェネレーター 無料」 の検索ボリュームが取れる
- wow が強い (リアルタイムに 3D が回って光る視覚インパクト)
#見た目をどう決めたか
直近 5本の 見た目 を書き出す:
wiki-orbit — bone paper light + ink + vermilion + ocean (古地図、 唯一の light theme)
fate-num — deep indigo + arcane gold + violet (serif italic, zodiac wheel)
roof-fund — drafting cyan + brass + red markup (sans, graph paper)
coin-stack — midnight navy + gold + teal (sans, trading dashboard)
pitch-flip — synthwave neon purple/magenta/cyan (sans, waveform)題材 「3D 文字を鍛える」 から モチーフ を引くと、 自然に 鍛冶屋 / 鋳造所 (forge / foundry) に行き着く。 既存にこの モチーフ は無い。
採用 3 要素:
- 配色: charcoal
#1a1817+ obsidian#0a0a09+ ember orange#ff6b35+ steel gray#a0a4a8+ brass#c9a445 - 18 本の中で 唯一の warm-dark industrial 配色。 既存の暖色系 (pitch-flip synthwave / coin-stack gold / py-pad yellow-orange) と並べても明確に違う (synthwave magenta + cyan vs ember-only / py-pad は背景が deep navy で全く違う)
- モチーフ: 鍛冶屋 / forge — sparks animation (8 個の faint particle が hero に浮遊)、 anvil 風 stamp (
FORGE-3D · TEXT-GEOMETRY · v1)、 ember glow を canvas 下から放射、 industrial grid 不要 (ノイズになるので避けた) - typography: Space Grotesk 800 weight uppercase で hero title (
FORGEを ember グラデで 144px)、 JetBrains Mono は labels に 0.28em〜0.32em tracking。 既存はだいたい 600 weight + sans casual だった中で 重い industrial weight に振った
「サイト共通の色をサービス内の主役の色に使わない」 という決めごとにも触れない (シェル mint cyan、 こちらは ember orange、 競合しない)。
#技術スタック
#Three.js (npm)
import * as THREE from "three"
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js"
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js"Three.js core (~150KB gzip) を dynamic import 経由で SSR 無しに lazy load。 ScrollView の中に出るまで bundle に乗らない設計。 OrbitControls / FontLoader / TextGeometry は examples/jsm/* から個別 import (tree-shake friendly)。
#TextGeometry + 5 材質
const geom = new TextGeometry(text, {
font,
size: 56,
depth: opts.depth, // 5〜120
bevelEnabled: opts.bevel > 0,
bevelThickness: opts.bevel * 0.5,
bevelSize: opts.bevel * 0.35,
bevelSegments: 4,
curveSegments: 8,
})
geom.center材質は MeshStandardMaterial (matte / metal / chrome) と MeshPhysicalMaterial (glass with transmission)、 emissive を上げた neon は MeshStandardMaterial の emissive プロパティで自発光。
#ライティング
const keyLight = new THREE.DirectionalLight(0xffe9c8, 2.4) // warm key
const rimLight = new THREE.DirectionalLight(0xff7038, 1.8) // ember rim (テーマ色)
const fillLight = new THREE.DirectionalLight(0x80aaff, 0.7) // cool fill (ハイライト)
const ambient = new THREE.AmbientLight(0xffffff, 0.22)ACES Filmic トーンマッピング + outputColorSpace = sRGB で 「色が暗くベタっとせず、 ハイライトが綺麗に転ぶ」 設定。
#PNG export
renderer.setSize(1080, 1080, false) // 描画解像度を一時的に 1080 に
camera.aspect = 1
camera.updateProjectionMatrix
renderer.render(scene, camera)
const blob = await new Promise<Blob>((resolve) =>
renderer.domElement.toBlob((b) => resolve(b!), "image/png")
)
// restore sizeWebGLRenderer の preserveDrawingBuffer: true を有効にして toBlob を許可。 export 後に元のサイズに戻す。 1080 は SNS アイコン / バナー で使いやすいサイズ。
#まだやっていないこと
- 日本語フォント (Noto Sans JP / 源ノ角ゴシック の typeface 化)。 1 フォント ~10MB と重いので CDN 配信か On-Demand DL で
- SVG vector export (Three.js の SVGRenderer 経由、 ただし PBR 材質は再現不能)
- 4K / 任意比率 PNG、 アニメ GIF / WebM 録画
- 環境マップ (HDR equirectangular) でクロム反射がもっとリアルに
- 共有 URL (
?text=&material=&color=) で SNS シェア後の再現 - 複数行レイアウト / グラデーション材質 / 木目背景
[ ./next_action ]
読んだら、 TypeForge を実際に動かす。
この開発ログは TypeForge をどう作ったかの記録です。 読み終わったらそのままサービス本体へ戻って、 実物で価値を確かめてください。