08ターミナルフッター
インク色の背景の上でうっすらしたノイズがフレームごとに位置を変えて点滅し、リンクの区画はデータ表示のように整理され、上端の角にブラケットが残ります。
使いどころマルチカラムフッター・サイトマップの整理
노이즈 플리커브래킷 코너모노스페이스 링크

<main class="stage">
<footer class="footerhud is-demo">
<span class="footerhud__corner footerhud__corner--tl" aria-hidden="true"></span>
<span class="footerhud__corner footerhud__corner--tr" aria-hidden="true"></span>
<div class="footerhud__noise" aria-hidden="true"></div>
<div class="footerhud__cols">
<div class="footerhud__col">
<p class="footerhud__head">SYSTEM</p>
<ul>
<li>ダッシュボード</li>
<li>通知設定</li>
</ul>
</div>
<div class="footerhud__col">
<p class="footerhud__head">SUPPORT</p>
<ul>
<li>お問い合わせ</li>
<li>利用ガイド</li>
</ul>
</div>
<div class="footerhud__col">
<p class="footerhud__head">LEGAL</p>
<ul>
<li>利用規約</li>
<li>プライバシーポリシー</li>
</ul>
</div>
</div>
<p class="footerhud__copy">SENTRY © 2026</p>
</footer>
</main>@use "../../../../site/static/demo-tokens" as *;
$duration: $dur-loop; // 노이즈 플리커 프레임 스텝의 한 주기
$easing: $ease-out; // 브래킷이 맥동하는 곡선
$color: $stage-yellow; // 호박색 터미널 강조색
@include stage($stage-paper);
.footerhud {
position: relative;
box-sizing: border-box;
width: clamp(260px, 88vw, 460px);
padding: $sp-6 $sp-5 $sp-4;
border-radius: $r-card;
background: $subject-ink;
box-shadow: 0 0 0 1px rgba($color, .4), 0 0 24px rgba($color, .16);
overflow: hidden;
}
.footerhud__noise {
position: absolute;
inset: 0;
pointer-events: none;
opacity: .06;
background: repeating-linear-gradient(45deg, rgba($color, .9) 0 1px, rgba($color, 0) 1px 4px);
background-size: 12px 12px;
animation: noiseFlicker $duration steps(8) infinite;
}
@keyframes noiseFlicker {
0% { background-position: 0 0; }
100% { background-position: 120px 84px; }
}
.footerhud__corner {
position: absolute;
width: 16px;
height: 16px;
pointer-events: none;
border-color: $color;
border-style: solid;
border-width: 0;
animation: cornerPulse $duration $easing infinite;
}
.footerhud__corner--tl { top: $sp-2; left: $sp-2; border-top-width: 2px; border-left-width: 2px; transform-origin: top left; } // 규칙8: 괄호 꼭짓점 모서리 고정
.footerhud__corner--tr { top: $sp-2; right: $sp-2; border-top-width: 2px; border-right-width: 2px; transform-origin: top right; animation-delay: -.15s; } // 규칙8: 괄호 꼭짓점 모서리 고정
@keyframes cornerPulse {
0%, 100% { transform: scale(.55); opacity: .35; }
50% { transform: scale(1); opacity: 1; }
}
.footerhud__cols {
position: relative;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: $sp-3;
margin: 0 0 $sp-4;
}
.footerhud__col {
min-width: 0;
}
.footerhud__head {
margin: 0 0 $sp-2;
color: $color;
font-family: "Courier New", monospace;
font-weight: 700;
font-size: clamp(9px, 2.2vw, 10px);
line-height: 1;
letter-spacing: .1em;
}
.footerhud__col ul {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: $sp-1;
}
.footerhud__col li {
color: rgba($subject-cream, .7);
font-weight: 500;
font-size: clamp(10px, 2.4vw, 11px);
line-height: 1.4;
font-family: inherit;
}
.footerhud__copy {
position: relative;
margin: 0;
padding-top: $sp-3;
border-top: 1px solid rgba($color, .18);
color: rgba($subject-cream, .72); // 잉크 면 위 9.18:1 — .4 는 3.66 으로 미달
font-family: "Courier New", monospace;
font-weight: 400;
font-size: clamp(9px, 2.2vw, 10px);
line-height: 1;
letter-spacing: .04em;
}
@media (prefers-reduced-motion: reduce) {
.footerhud__noise, .footerhud__corner {
animation: none !important;
}
.footerhud__noise { opacity: .03; }
.footerhud__corner { transform: scale(1); opacity: 1; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #ffffff;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.footerhud {
position: relative;
box-sizing: border-box;
width: clamp(260px, 88vw, 460px);
padding: 24px 20px 16px;
border-radius: 16px;
background: #17141a;
box-shadow: 0 0 0 1px rgba(255, 210, 63, 0.4), 0 0 24px rgba(255, 210, 63, 0.16);
overflow: hidden;
}
.footerhud__noise {
position: absolute;
inset: 0;
pointer-events: none;
opacity: 0.06;
background: repeating-linear-gradient(45deg, rgba(255, 210, 63, 0.9) 0 1px, rgba(255, 210, 63, 0) 1px 4px);
background-size: 12px 12px;
animation: noiseFlicker 2s steps(8) infinite;
}
@keyframes noiseFlicker {
0% {
background-position: 0 0;
}
100% {
background-position: 120px 84px;
}
}
.footerhud__corner {
position: absolute;
width: 16px;
height: 16px;
pointer-events: none;
border-color: #ffd23f;
border-style: solid;
border-width: 0;
animation: cornerPulse 2s ease-out infinite;
}
.footerhud__corner--tl {
top: 8px;
left: 8px;
border-top-width: 2px;
border-left-width: 2px;
transform-origin: top left;
}
.footerhud__corner--tr {
top: 8px;
right: 8px;
border-top-width: 2px;
border-right-width: 2px;
transform-origin: top right;
animation-delay: -0.15s;
}
@keyframes cornerPulse {
0%, 100% {
transform: scale(0.55);
opacity: 0.35;
}
50% {
transform: scale(1);
opacity: 1;
}
}
.footerhud__cols {
position: relative;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin: 0 0 16px;
}
.footerhud__col {
min-width: 0;
}
.footerhud__head {
margin: 0 0 8px;
color: #ffd23f;
font-family: "Courier New", monospace;
font-weight: 700;
font-size: clamp(9px, 2.2vw, 10px);
line-height: 1;
letter-spacing: 0.1em;
}
.footerhud__col ul {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 4px;
}
.footerhud__col li {
color: rgba(255, 247, 230, 0.7);
font-weight: 500;
font-size: clamp(10px, 2.4vw, 11px);
line-height: 1.4;
font-family: inherit;
}
.footerhud__copy {
position: relative;
margin: 0;
padding-top: 12px;
border-top: 1px solid rgba(255, 210, 63, 0.18);
color: rgba(255, 247, 230, 0.72);
font-family: "Courier New", monospace;
font-weight: 400;
font-size: clamp(9px, 2.2vw, 10px);
line-height: 1;
letter-spacing: 0.04em;
}
@media (prefers-reduced-motion: reduce) {
.footerhud__noise, .footerhud__corner {
animation: none !important;
}
.footerhud__noise {
opacity: 0.03;
}
.footerhud__corner {
transform: scale(1);
opacity: 1;
}
}import type { CSSProperties } from "react";
import styles from "./FooterHud.module.scss";
export type FooterHudColumn = { head: string; links: string[] };
export type FooterHudProps = {
columns?: FooterHudColumn[];
copy?: string;
duration?: number;
easing?: string;
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
const defaultColumns: FooterHudColumn[] = [
{ head: "SYSTEM", links: ["대시보드", "알림 설정"] },
{ head: "SUPPORT", links: ["문의하기", "이용 가이드"] },
{ head: "LEGAL", links: ["이용약관", "개인정보처리방침"] },
];
export default function FooterHud({
columns = defaultColumns,
copy = "SENTRY © 2026",
duration = 2000,
easing = "ease-out",
color = "#ffd23f",
}: FooterHudProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
return (
<footer className={styles.footer} style={vars}>
<span className={`${styles.corner} ${styles.cornerTl}`} aria-hidden="true" />
<span className={`${styles.corner} ${styles.cornerTr}`} aria-hidden="true" />
<div className={styles.noise} aria-hidden="true" />
<div className={styles.cols}>
{columns.map((col) => (
<div key={col.head} className={styles.col}>
<p className={styles.head}>{col.head}</p>
<ul>
{col.links.map((link) => <li key={link}>{link}</li>)}
</ul>
</div>
))}
</div>
<p className={styles.copy}>{copy}</p>
</footer>
);
}08 ターミナルフッター — 計測 累積面積 29.669% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · HUD デザインとは?画面に見つめ返される9パーツ
このデモが属する記事
HUD デザインとは?画面に見つめ返される9パーツHUD デザインとは、ゲームやSF映画の照準器やレーダーのように、座標や状態の数値を画面に重ねて表示し、まるで自分が見つめ返されているような印象を与えるインターフェース手法です。この記事では、その監視カメラのような雰囲気をそのまま動くランデ この記事のデモをすべて見る


