posimai-root/docs/posimai-bg.md

269 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Posimai 背景スタイル — コピペ用リファレンス
新規アプリで Station/Guard と同じ背景を使いたい時はここからコピーする。
AI への指示は「`docs/posimai-bg.md` の背景スタイルを適用して」だけで OK。
---
## 何が入っているか
| 要素 | 内容 |
|------|------|
| 背景色 | `#0C1221`Termius 系ダークブルー) |
| グリッド線 | 48px 格子、極薄白 |
| 上部グロー | シアン+アクセントカラーのグラデーション |
| バイナリオーロラ | 0/1 が降るキャンバスアニメーションStation と同仕様) |
| フォント | InterUI + JetBrains Monoコード・キャンバス |
アクセントカラーだけ各アプリで差し替えるGuard は `#F97316`、Station は `#22D3EE` など)。
---
## 1. layout.tsx — フォント読み込み
```tsx
import { Inter, JetBrains_Mono } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
weight: ['300', '400', '500', '600'],
display: 'swap',
variable: '--font-sans',
});
const jetbrainsMono = JetBrains_Mono({
subsets: ['latin'],
weight: ['400', '500'],
display: 'swap',
variable: '--font-mono',
});
// body の className に両方渡す
<body className={`${inter.variable} ${jetbrainsMono.variable}`}>
```
---
## 2. globals.css — 背景スタイル一式
```css
@theme inline {
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
}
:root {
--bg: #0C1221;
--surface: #111827;
--surface2: #1A2332;
--border: #1F2D40;
/* アクセントカラーはアプリごとに変える */
--accent: #22D3EE; /* 例: Station はシアン */
--grid-line: rgba(255, 255, 255, 0.028);
}
body {
background: var(--bg);
font-family: var(--font-sans);
-webkit-font-smoothing: antialiased;
}
/* グリッド線 */
body::before {
content: '';
position: fixed;
inset: 0;
background-image:
linear-gradient(var(--grid-line) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
background-size: 48px 48px;
pointer-events: none;
z-index: 0;
}
/* 上部グロー(アクセントカラーを参照) */
body::after {
content: '';
position: fixed;
top: 0; left: 0; right: 0;
height: 480px;
background: radial-gradient(
ellipse 70% 45% at 50% -5%,
color-mix(in srgb, var(--accent) 8%, transparent) 0%,
transparent 70%
);
pointer-events: none;
z-index: 0;
}
/* コンテンツをオーロラの上に */
body > * {
position: relative;
z-index: 1;
}
```
---
## 3. BinaryAurora.tsx — コピペ用完全版
色帯BANDSの hue を変えるとアプリのカラーに合わせられる。
現在値は Station と同じシアン(185) / パープル(265) / グリーン(150)。
```tsx
'use client';
import { useEffect, useRef } from 'react';
export function BinaryAurora() {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
const FONT_SIZE = 14;
// 色帯: hue を変えてアプリのカラーに合わせる
// シアン/パープル/グリーンStation・Guard 共通)
const BANDS = [
{ hue: 185, sat: 90, x: 0.15, speed: 0.00018, phase: 0 },
{ hue: 265, sat: 80, x: 0.38, speed: 0.00013, phase: 1.5 },
{ hue: 185, sat: 85, x: 0.62, speed: 0.00020, phase: 3.0 },
{ hue: 150, sat: 70, x: 0.80, speed: 0.00015, phase: 4.2 },
];
type Col = { y: number; speed: number; len: number; chars: string[]; opacity: number };
let cols: Col[] = [];
let t = 0;
let raf: number;
const resize = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const numCols = Math.ceil(canvas.width / FONT_SIZE);
while (cols.length < numCols) {
cols.push({
y: Math.random() * canvas.height,
speed: 1.0 + Math.random() * 3.2,
len: 8 + Math.floor(Math.random() * 22),
chars: [],
opacity: 0.28 + Math.random() * 0.50,
});
}
if (cols.length > numCols) cols.length = numCols;
};
resize();
window.addEventListener('resize', resize);
function getBandColor(x: number, now: number): { hue: number; sat: number; alpha: number } {
const xf = x / (canvas?.width ?? 1);
let best = BANDS[0];
let bestDist = Infinity;
for (const b of BANDS) {
const bx = b.x + Math.sin(now * b.speed + b.phase) * 0.12;
const dist = Math.abs(xf - bx);
if (dist < bestDist) { bestDist = dist; best = b; }
}
const bx = best.x + Math.sin(now * best.speed + best.phase) * 0.12;
const alpha = Math.max(0, 1 - Math.abs(xf - bx) / 0.22);
return { hue: best.hue, sat: best.sat, alpha };
}
const draw = () => {
t++;
raf = requestAnimationFrame(draw);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = `${FONT_SIZE}px 'JetBrains Mono', monospace`;
cols.forEach((col, i) => {
const x = i * FONT_SIZE;
const band = getBandColor(x, t);
for (let j = 0; j < col.len; j++) {
const cy = col.y - j * FONT_SIZE;
if (cy < -FONT_SIZE || cy > canvas.height + FONT_SIZE) continue;
if (!col.chars[j] || (t % 8 === 0 && Math.random() < 0.05)) {
col.chars[j] = Math.random() < 0.5 ? '1' : '0';
}
const ch = col.chars[j];
const trailAlpha = (1 - j / col.len) * col.opacity;
const finalAlpha = trailAlpha * (band.alpha * 0.7 + 0.15);
if (j === 0) {
ctx.fillStyle = `hsla(${band.hue},${band.sat}%,94%,${Math.min(1, finalAlpha * 2.2)})`;
} else if (ch === '1') {
ctx.fillStyle = `hsla(${band.hue},${band.sat}%,65%,${finalAlpha})`;
} else {
ctx.fillStyle = `hsla(${(band.hue + 30) % 360},${Math.round(band.sat * 0.6)}%,45%,${finalAlpha * 0.55})`;
}
ctx.fillText(ch, x, cy);
}
col.y += col.speed;
if (col.y - col.len * FONT_SIZE > canvas.height) {
col.y = -FONT_SIZE * 2;
col.speed = 1.0 + Math.random() * 3.2;
col.len = 8 + Math.floor(Math.random() * 22);
col.chars = [];
col.opacity = 0.28 + Math.random() * 0.50;
}
});
};
raf = requestAnimationFrame(draw);
return () => {
cancelAnimationFrame(raf);
window.removeEventListener('resize', resize);
};
}, []);
return (
<canvas
ref={canvasRef}
aria-hidden="true"
style={{
position: 'fixed',
inset: 0,
opacity: 1,
pointerEvents: 'none',
zIndex: 0,
}}
/>
);
}
```
### 使い方
```tsx
// layout.tsx または page.tsx に追加するだけ
import { BinaryAurora } from '@/components/BinaryAurora';
export default function Layout({ children }) {
return (
<>
<BinaryAurora />
{children}
</>
);
}
```
---
## 4. カスタマイズチートシート
| 変えたいもの | 場所 | 変更内容 |
|-------------|------|---------|
| 雨の色 | `BANDS[*].hue` | オレンジ系は 18〜42、シアンは 185、パープルは 265 |
| 雨の速さ | `speed: 1.0 + Math.random() * 3.2` | 数値を大きくすると速い |
| 雨の長さ | `len: 8 + Math.floor(Math.random() * 22)` | 数値を大きくすると長いトレイル |
| 背景色 | `--bg` CSS 変数 | `#0C1221` 標準。より暗くしたければ `#080E1A` など |
| 上部グロー | `body::after``--accent` | アクセントカラーに追従する |
| キャンバス全体の明るさ | `canvas opacity` | `0.5〜1.0` の範囲で調整 |