<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>기계설계 &#8211; MyEngNote</title>
	<atom:link href="https://myengnote.com/tag/%ea%b8%b0%ea%b3%84%ec%84%a4%ea%b3%84/feed/" rel="self" type="application/rss+xml" />
	<link>https://myengnote.com</link>
	<description></description>
	<lastBuildDate>Wed, 08 Jul 2026 04:43:13 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.2</generator>
	<item>
		<title>열팽창 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/thermal-expansion-calculator-simulator/</link>
					<comments>https://myengnote.com/thermal-expansion-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Tue, 09 Jun 2026 19:52:51 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[선팽창계수]]></category>
		<category><![CDATA[열역학]]></category>
		<category><![CDATA[열팽창]]></category>
		<category><![CDATA[재료역학]]></category>
		<guid isPermaLink="false">https://myengnote.com/thermal-expansion-calculator-simulator/</guid>

					<description><![CDATA[온도 변화에 따른 다양한 금속 봉의 길이 팽창을 실시간 시각화하고, 선팽창 공식과 마이크로 미터 단위의 변위를 물리 모델링과 아토믹 진동으로 보여주는 2D 시뮬레이터입니다.]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 열팽창 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for thermalexpansion-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .thermalexpansion-calculator-wrapper *, .thermalexpansion-calculator-wrapper *::before, .thermalexpansion-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .thermalexpansion-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7;
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777;
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .thermalexpansion-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.12;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.1; }
            100% { transform: scale(1.18) translate(40px, 40px); opacity: 0.18; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-muted));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: #0284c7; }
        .text-magenta { color: #db2777; }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .range-helper {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within {
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .custom-select {
            width: 100%;
            background: #f8fafc;
            border: 1px solid var(--color-border);
            outline: none;
            color: #0f172a;
            padding: 10px 14px;
            font-family: var(--font-body);
            font-size: 14px;
            font-weight: 600;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.2s ease;
        }
        .custom-select:focus {
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 6px 0;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            background: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan);
            transition: transform 0.1s ease;
        }
        .custom-slider::-webkit-slider-thumb:hover {
            transform: scale(1.2);
        }
        .presets-section {
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: grid;
            grid-template-columns: 1fr;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 10px 14px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: #0284c7;
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
        }
        .preset-name {
            font-size: 12px;
            font-weight: 600;
        }
        .simulation-panel {
            grid-column: 2;
            align-self: start;
        }
        .simulation-panel .panel-header {
            justify-content: space-between;
        }
        .canvas-scale-indicator {
            font-size: 11px;
            color: var(--color-text-muted);
            background: rgba(0, 0, 0, 0.02);
            padding: 4px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
        }
        .canvas-wrapper {
            position: relative;
            width: 100%;
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%);
            border: 1px solid rgba(0, 0, 0, 0.06);
            border-radius: 16px;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #physics-canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 16 / 8;
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(219, 39, 119, 0.08) 0%, rgba(124, 58, 237, 0.03) 100%);
            border: 1px solid rgba(219, 39, 119, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: #db2777;
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 28px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(219, 39, 119, 0.2);
            background: rgba(219, 39, 119, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
        }
        .result-card:hover .card-icon {
            color: #db2777;
            border-color: rgba(219, 39, 119, 0.3);
            background: rgba(219, 39, 119, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 10px;
            font-weight: 600;
            color: var(--color-text-muted);
            text-transform: uppercase;
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 16px;
            color: var(--color-text-main);
        }
        .formula-card {
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            font-size: 12px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        .formula-equation {
            font-family: monospace;
            color: #0284c7;
            font-size: 13px;
            background: #f8fafc;
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        @container expansion-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1.2fr;
                gap: 20px;
            }
        }
        @container expansion-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.thermalexpansion-calculator-wrapper .app-main-grid,
.thermalexpansion-calculator-wrapper .main-grid,
.thermalexpansion-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.thermalexpansion-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.thermalexpansion-calculator-wrapper .simulation-panel,
.thermalexpansion-calculator-wrapper .canvas-panel,
.thermalexpansion-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.thermalexpansion-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.thermalexpansion-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.thermalexpansion-calculator-wrapper .simulation-results-section .ratio-readout-box,
.thermalexpansion-calculator-wrapper .simulation-results-section .re-readout-box,
.thermalexpansion-calculator-wrapper .simulation-results-section .status-readout-box,
.thermalexpansion-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.thermalexpansion-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.thermalexpansion-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.thermalexpansion-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .thermalexpansion-calculator-wrapper .app-main-grid,
    .thermalexpansion-calculator-wrapper .main-grid,
    .thermalexpansion-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .thermalexpansion-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .thermalexpansion-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .thermalexpansion-calculator-wrapper .simulation-panel,
    .thermalexpansion-calculator-wrapper .canvas-panel,
    .thermalexpansion-calculator-wrapper .sim-panel,
    .thermalexpansion-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .thermalexpansion-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .thermalexpansion-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .thermalexpansion-calculator-wrapper .simulation-results-section .re-readout-box,
    .thermalexpansion-calculator-wrapper .simulation-results-section .status-readout-box,
    .thermalexpansion-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .thermalexpansion-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .thermalexpansion-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.thermalexpansion-calculator-wrapper .app-container,
.thermalexpansion-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.thermalexpansion-calculator-wrapper .simulation-results-section .formula-card,
.thermalexpansion-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 8px !important;
}
.thermalexpansion-calculator-wrapper .simulation-results-section .formula-card h4,
.thermalexpansion-calculator-wrapper .results-panel .formula-card h4 {
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
}
.thermalexpansion-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="thermalexpansion-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-temperature-three-quarters"></i></div>
                <div>
                    <h1>THERMAL EXPANSION</h1>
                    <div class="subtitle">금속 열팽창 계수 계산기 &#038; 실시간 2D 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">물리 연산 엔진 작동중</div>
            </div>
        </header>
        <div class="app-main-grid">
            <!-- Left Column: Controls -->
            <div class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>시뮬레이션 제어</h2>
                </div>
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-cubes text-cyan"></i> 대상 금속 재질</label>
                    </div>
                    <select id="select-material" class="custom-select">
                        <option value="steel">탄소강 (Steel)</option>
                        <option value="copper">구리 (Copper)</option>
                        <option value="aluminum">알루미늄 (Aluminum)</option>
                        <option value="brass">황동 (Brass)</option>
                    </select>
                </div>
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-ruler-horizontal text-cyan"></i> 초기 길이 (L₀)</label>
                        <span class="range-helper">Min: 1.0m / Max: 10.0m</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-l0" class="custom-number-input" value="5.0" step="0.1" min="1.0" max="10.0">
                        <span class="unit-badge">m</span>
                    </div>
                    <input type="range" id="slider-l0" class="custom-slider" value="5.0" min="1.0" max="10.0" step="0.1">
                </div>
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-temperature-low text-cyan"></i> 초기 온도 (T₁)</label>
                        <span class="range-helper">Min: -50°C / Max: 100°C</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-t1" class="custom-number-input" value="20" step="1" min="-50" max="100">
                        <span class="unit-badge">°C</span>
                    </div>
                    <input type="range" id="slider-t1" class="custom-slider" value="20" min="-50" max="100" step="1">
                </div>
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-temperature-high text-magenta"></i> 최종 온도 (T₂)</label>
                        <span class="range-helper">Min: -50°C / Max: 500°C</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-t2" class="custom-number-input" value="200" step="1" min="-50" max="500">
                        <span class="unit-badge">°C</span>
                    </div>
                    <input type="range" id="slider-t2" class="custom-slider" value="200" min="-50" max="500" step="1">
                </div>
                <div class="presets-section">
                    <h3><i class="fa-solid fa-fire-burner text-purple"></i> 급속 시나리오 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn" data-preset="heat">
                            <div class="preset-icon"><i class="fa-solid fa-fire"></i></div>
                            <div class="preset-details"><span class="preset-name">고온 가열 시험</span><span class="preset-spec">500°C</span></div>
                        </button>
                        <button class="preset-btn" data-preset="normal">
                            <div class="preset-icon"><i class="fa-solid fa-leaf"></i></div>
                            <div class="preset-details"><span class="preset-name">표준 대기온 상태</span><span class="preset-spec">20°C</span></div>
                        </button>
                        <button class="preset-btn" data-preset="cold">
                            <div class="preset-icon"><i class="fa-solid fa-snowflake"></i></div>
                            <div class="preset-details"><span class="preset-name">극저온 빙결 시험</span><span class="preset-spec">-50°C</span></div>
                        </button>
                    </div>
                </div>
            </div>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <div class="panel simulation-panel">
                                <div class="panel-header">
                                    <div>
                                        <i class="fa-solid fa-chart-line text-cyan"></i>
                                        <h2>실시간 거시/미시 변형 시뮬레이터</h2>
                                    </div>
                                    <span id="canvas-scale-indicator" class="canvas-scale-indicator">배율: 100배 과장</span>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas"></canvas>
                                </div>
                                <!-- Integrated Results Analysis Section -->
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                            <div class="ratio-title">길이 변화량 (ΔL)</div>
                                            <div id="txt-delta-l" class="ratio-value">+15.30 mm</div>
                                        </div>
                                <div class="results-grid">
                                        <!-- Temperature Diff -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-temperature-half text-cyan"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">온도 변화폭 (ΔT)</span>
                                                <span id="txt-delta-t" class="card-value">180 °C</span>
                                            </div>
                                        </div>
                                        <!-- Final Length -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-ruler-horizontal text-purple"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">최종 전체 길이 (L)</span>
                                                <span id="txt-final-l" class="card-value">5.0153 m</span>
                                            </div>
                                        </div>
                                        <!-- Thermal Strain -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-percent text-magenta"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">열변형률 (Thermal Strain)</span>
                                                <span id="txt-strain" class="card-value">0.306 %</span>
                                            </div>
                                        </div>
                                        <!-- Thermal Stress -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-compress text-success"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">구속 시 온도응력 (Thermal Stress)</span>
                                                <span id="txt-stress" class="card-value">414.0 MPa</span>
                                            </div>
                                        </div>
                                    </div>
                                <div class="formula-card">
                                            <h4><i class="fa-solid fa-circle-info text-cyan"></i> 선팽창 계산 공식</h4>
                                            <div class="formula-equation">
                                                ΔL = α × L₀ × ΔT
                                            </div>
                                        </div>
                            </div>
                </div>
            </div>
        </div>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- JavaScript Core Simulator Engine -->
    </div>
</div>
<script>
        (function() {
            let isInit = false;
            function initSimulator() {
                if (isInit) return;
                const canvas = document.getElementById('physics-canvas');
                if (!canvas) return;
                const ctx = canvas.getContext('2d');
                if (!ctx) return;
                isInit = true;
                window.__thermalexpansion_initialized = true;
                // DOM elements
                const selectMaterial = document.getElementById('select-material');
                const sliderL0 = document.getElementById('slider-l0');
                const inputL0 = document.getElementById('input-l0');
                const sliderT1 = document.getElementById('slider-t1');
                const inputT1 = document.getElementById('input-t1');
                const sliderT2 = document.getElementById('slider-t2');
                const inputT2 = document.getElementById('input-t2');
                const presetBtns = document.querySelectorAll('.preset-btn');
                const txtDeltaL = document.getElementById('txt-delta-l');
                const txtDeltaT = document.getElementById('txt-delta-t');
                const txtFinalL = document.getElementById('txt-final-l');
                const txtStrain = document.getElementById('txt-strain');
                const txtStress = document.getElementById('txt-stress');
                // Simulation State
                const state = {
                    material: 'steel',
                    l0: 5.0,
                    t1: 20,
                    t2: 200,
                    alpha: 11.5e-6,
                    youngsModulus: 200e9, // Pa
                    density: 7850,
                    colorGradStart: '#94a3b8',
                    colorGradEnd: '#475569',
                    particles: []
                };
                const materialProperties = {
                    steel: {
                        alpha: 11.5e-6,
                        E: 200e9,
                        density: 7850,
                        c1: '#a1a1aa',
                        c2: '#52525b'
                    },
                    copper: {
                        alpha: 17.0e-6,
                        E: 110e9,
                        density: 8960,
                        c1: '#fb923c',
                        c2: '#c2410c'
                    },
                    aluminum: {
                        alpha: 23.0e-6,
                        E: 70e9,
                        density: 2700,
                        c1: '#cbd5e1',
                        c2: '#64748b'
                    },
                    brass: {
                        alpha: 19.0e-6,
                        E: 90e9,
                        density: 8500,
                        c1: '#fde047',
                        c2: '#ca8a04'
                    }
                };
                // Retina Display Canvas adaptation
                function resizeCanvas() {
                    const rect = canvas.getBoundingClientRect();
                    const dpr = window.devicePixelRatio || 1;
                    canvas.width = rect.width * dpr;
                    canvas.height = rect.height * dpr;
                    ctx.scale(dpr, dpr);
                }
                resizeCanvas();
                window.addEventListener('resize', resizeCanvas);
                setTimeout(resizeCanvas, 300);
                // Input sync handlers
                function syncL0FromSlider() {
                    const val = parseFloat(sliderL0.value);
                    inputL0.value = val.toFixed(1);
                    state.l0 = val;
                    clearPresets();
                    updateCalculations();
                }
                function syncL0FromInput() {
                    let val = parseFloat(inputL0.value);
                    if (isNaN(val)) {
                        val = 5.0;
                    }
                    if (val < 1.0) {
                        val = 1.0;
                    }
                    if (val > 10.0) {
                        val = 10.0;
                    }
                    sliderL0.value = val;
                    state.l0 = val;
                    clearPresets();
                    updateCalculations();
                }
                function syncT1FromSlider() {
                    const val = parseInt(sliderT1.value);
                    inputT1.value = val;
                    state.t1 = val;
                    clearPresets();
                    updateCalculations();
                }
                function syncT1FromInput() {
                    let val = parseInt(inputT1.value);
                    if (isNaN(val)) {
                        val = 20;
                    }
                    if (val < -50) {
                        val = -50;
                    }
                    if (val > 100) {
                        val = 100;
                    }
                    sliderT1.value = val;
                    state.t1 = val;
                    clearPresets();
                    updateCalculations();
                }
                function syncT2FromSlider() {
                    const val = parseInt(sliderT2.value);
                    inputT2.value = val;
                    state.t2 = val;
                    clearPresets();
                    updateCalculations();
                }
                function syncT2FromInput() {
                    let val = parseInt(inputT2.value);
                    if (isNaN(val)) {
                        val = 200;
                    }
                    if (val < -50) {
                        val = -50;
                    }
                    if (val > 500) {
                        val = 500;
                    }
                    sliderT2.value = val;
                    state.t2 = val;
                    clearPresets();
                    updateCalculations();
                }
                function handleMaterialChange() {
                    const selected = selectMaterial.value;
                    const props = materialProperties[selected];
                    if (props) {
                        state.material = selected;
                        state.alpha = props.alpha;
                        state.youngsModulus = props.E;
                        state.density = props.density;
                        state.colorGradStart = props.c1;
                        state.colorGradEnd = props.c2;
                    }
                    updateCalculations();
                }
                function loadPreset(presetKey) {
                    clearPresets();
                    presetBtns.forEach(btn => {
                        if (btn.dataset.preset === presetKey) {
                            btn.classList.add('active');
                        }
                    });
                    if (presetKey === 'heat') {
                        state.t1 = 20;
                        state.t2 = 500;
                    }
                    if (presetKey === 'normal') {
                        state.t1 = 20;
                        state.t2 = 20;
                    }
                    if (presetKey === 'cold') {
                        state.t1 = 20;
                        state.t2 = -50;
                    }
                    sliderT1.value = state.t1;
                    inputT1.value = state.t1;
                    sliderT2.value = state.t2;
                    inputT2.value = state.t2;
                    updateCalculations();
                }
                function clearPresets() {
                    presetBtns.forEach(btn => btn.classList.remove('active'));
                }
                // Math Model update
                function updateCalculations() {
                    const deltaT = state.t2 - state.t1;
                    const deltaL = state.alpha * state.l0 * deltaT * 1000; // mm
                    const finalL = state.l0 + (deltaL / 1000);
                    const strain = (state.alpha * deltaT) * 100; // %
                    const stress = state.youngsModulus * state.alpha * deltaT / 1e6; // MPa
                    txtDeltaT.innerText = `${deltaT} °C`;
                    if (deltaL >= 0) {
                        txtDeltaL.innerText = `+${deltaL.toFixed(3)} mm`;
                        txtDeltaL.style.color = '#db2777';
                    }
                    if (deltaL < 0) {
                        txtDeltaL.innerText = `${deltaL.toFixed(3)} mm`;
                        txtDeltaL.style.color = '#0284c7';
                    }
                    txtFinalL.innerText = `${finalL.toFixed(6)} m`;
                    txtStrain.innerText = `${strain.toFixed(4)} %`;
                    txtStress.innerText = `${stress.toFixed(1)} MPa`;
                }
                // Particle systems (Fire/Ice)
                class EffectParticle {
                    constructor(x, y, type) {
                        this.x = x;
                        this.y = y;
                        this.type = type; // 'fire' or 'cold'
                        this.size = Math.random() * 4 + 2;
                        this.vx = (Math.random() - 0.5) * 1.0;
                        if (type === 'fire') {
                            this.vy = -(Math.random() * 1.5 + 0.5);
                            this.life = Math.random() * 30 + 20;
                            const colors = ['#f97316', '#ef4444', '#f59e0b', '#ef4444'];
                            this.color = colors[Math.floor(Math.random() * colors.length)];
                        }
                        if (type === 'cold') {
                            this.vy = Math.random() * 1.2 + 0.3;
                            this.life = Math.random() * 40 + 30;
                            const colors = ['#38bdf8', '#0284c7', '#ffffff', '#e0f2fe'];
                            this.color = colors[Math.floor(Math.random() * colors.length)];
                        }
                        this.maxLife = this.life;
                    }
                    update() {
                        this.x += this.vx;
                        this.y += this.vy;
                        this.life--;
                    }
                    draw(c) {
                        const alpha = this.life / this.maxLife;
                        c.save();
                        c.globalAlpha = alpha;
                        c.fillStyle = this.color;
                        c.beginPath();
                        if (this.type === 'cold') {
                            c.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                            c.fill();
                        }
                        if (this.type === 'fire') {
                            c.beginPath();
                            c.moveTo(this.x, this.y - this.size);
                            c.lineTo(this.x + this.size, this.y + this.size);
                            c.lineTo(this.x - this.size, this.y + this.size);
                            c.closePath();
                            c.fill();
                        }
                        c.restore();
                    }
                }
                // Helper to draw dimensional arrowheads
                function drawArrowhead(c, x, y, angle) {
                    c.save();
                    c.translate(x, y);
                    c.rotate(angle);
                    c.beginPath();
                    c.moveTo(0, 0);
                    c.lineTo(-6, -3.5);
                    c.lineTo(-6, 3.5);
                    c.closePath();
                    c.fillStyle = c.strokeStyle;
                    c.fill();
                    c.restore();
                }
                // Render main loop
                function animate(timestamp) {
                    requestAnimationFrame(animate);
                    // Check and auto-fit canvas resolution to layout changes (prevents vertical stretch &#038; empty gaps)
                    const dpr = window.devicePixelRatio || 1;
                    const rect = canvas.getBoundingClientRect();
                    if (Math.abs(canvas.width - rect.width * dpr) > 1.5 || Math.abs(canvas.height - rect.height * dpr) > 1.5) {
                        resizeCanvas();
                    }
                    const width = canvas.width / dpr;
                    const height = canvas.height / dpr;
                    ctx.clearRect(0, 0, width, height);
                    // Blueprint Grid Lines
                    ctx.save();
                    ctx.strokeStyle = 'rgba(2, 132, 199, 0.05)';
                    ctx.lineWidth = 1;
                    for (let x = 0; x < width; x += 24) {
                        ctx.beginPath();
                        ctx.moveTo(x, 0);
                        ctx.lineTo(x, height);
                        ctx.stroke();
                    }
                    for (let y = 0; y < height; y += 24) {
                        ctx.beginPath();
                        ctx.moveTo(0, y);
                        ctx.lineTo(width, y);
                        ctx.stroke();
                    }
                    ctx.restore();
                    // Physics Expansion calculations
                    const deltaT = state.t2 - state.t1;
                    const deltaL = state.alpha * state.l0 * deltaT * 1000; // in mm
                    const finalL = state.l0 + (deltaL / 1000);
                    // Layout positions - dynamic auto-zoom based on canvas size
                    const startX = 60;
                    // Leave 240px for dial gauge and magnifier to prevent boundary overflow
                    const availWidth = (width - startX - 240); 
                    // Map l0 (1.0m to 10.0m) to baseWidth (35% to 65% of availWidth)
                    const maxBaseWidth = availWidth * 0.65;
                    const minBaseWidth = availWidth * 0.35;
                    const baseWidth = minBaseWidth + (state.l0 - 1.0) / 9.0 * (maxBaseWidth - minBaseWidth);
                    // Dynamic visual expansion scale: max 15% of availWidth at 1.5% thermal strain
                    const maxExpansionWidth = availWidth * 0.15;
                    const strainPct = state.alpha * deltaT;
                    const visualExpansion = (strainPct / 0.015) * maxExpansionWidth; 
                    const rodHeight = Math.max(25, Math.min(45, height * 0.105));
                    // Golden Vertical Centering: mathematically centers the rod, dimension lines, and particle overlays
                    const totalDrawHeight = rodHeight + 84;
                    const rodY = (height - totalDrawHeight) / 2 + 10;
                    const currentRodWidth = baseWidth + visualExpansion;
                    // Draw Left Anchor Bracket
                    ctx.save();
                    ctx.fillStyle = '#64748b';
                    ctx.fillRect(startX - 20, rodY - 15, 20, rodHeight + 30);
                    ctx.strokeStyle = '#334155';
                    ctx.lineWidth = 2;
                    ctx.strokeRect(startX - 20, rodY - 15, 20, rodHeight + 30);
                    // Hatch pattern on anchor
                    ctx.strokeStyle = 'rgba(255,255,255,0.2)';
                    ctx.lineWidth = 1.5;
                    for (let h = rodY - 10; h < rodY + rodHeight + 15; h += 8) {
                        ctx.beginPath();
                        ctx.moveTo(startX - 18, h);
                        ctx.lineTo(startX - 2, h - 8);
                        ctx.stroke();
                    }
                    ctx.restore();
                    // Particles spawn (Flame underneath, or ice falling from top)
                    if (state.t2 > state.t1) {
                        // Spawn burner flame
                        const heatIntensity = Math.min((state.t2 - state.t1) / 300, 1.5);
                        if (Math.random() < 0.25 * heatIntensity) {
                            const px = startX + Math.random() * currentRodWidth;
                            state.particles.push(new EffectParticle(px, rodY + rodHeight + 15, 'fire'));
                        }
                    }
                    if (state.t2 < state.t1) {
                        // Spawn cold snowflake drop
                        const coldIntensity = Math.min((state.t1 - state.t2) / 100, 1.5);
                        if (Math.random() < 0.25 * coldIntensity) {
                            const px = startX + Math.random() * currentRodWidth;
                            state.particles.push(new EffectParticle(px, rodY - 20, 'cold'));
                        }
                    }
                    // Update &#038; Draw Particles
                    state.particles = state.particles.filter(p => p.life > 0);
                    state.particles.forEach(p => {
                        p.update();
                        p.draw(ctx);
                    });
                    // Draw heating element or cooling block visualizers
                    if (state.t2 > state.t1) {
                        ctx.fillStyle = 'rgba(239, 68, 68, 0.05)';
                        ctx.fillRect(startX, rodY + rodHeight + 2, currentRodWidth, 12);
                    }
                    if (state.t2 < state.t1) {
                        ctx.fillStyle = 'rgba(56, 189, 248, 0.05)';
                        ctx.fillRect(startX, rodY - 14, currentRodWidth, 12);
                    }
                    // Draw the Metal Rod itself
                    ctx.save();
                    // 1. Draw base initial length segment
                    const metalGrad = ctx.createLinearGradient(startX, rodY, startX, rodY + rodHeight);
                    metalGrad.addColorStop(0, state.colorGradStart);
                    metalGrad.addColorStop(0.3, '#ffffff');
                    metalGrad.addColorStop(1, state.colorGradEnd);
                    ctx.fillStyle = metalGrad;
                    // Draw base width (L0 portion)
                    if (visualExpansion >= 0) {
                        ctx.fillRect(startX, rodY, baseWidth, rodHeight);
                        // 2. Draw expanded segment (with pinkish/red overlay + stripes for clarity)
                        ctx.fillStyle = 'rgba(219, 39, 119, 0.2)';
                        ctx.fillRect(startX + baseWidth, rodY, visualExpansion, rodHeight);
                        ctx.strokeStyle = 'rgba(219, 39, 119, 0.4)';
                        ctx.lineWidth = 1.5;
                        for (let bx = startX + baseWidth; bx < startX + baseWidth + visualExpansion; bx += 8) {
                            ctx.beginPath();
                            ctx.moveTo(bx, rodY);
                            ctx.lineTo(bx + 6, rodY + rodHeight);
                            ctx.stroke();
                        }
                    } else {
                        // Rod has contracted (visualExpansion is negative)
                        ctx.fillRect(startX, rodY, currentRodWidth, rodHeight);
                        // Show contracted missing region as dotted translucent blue box
                        ctx.strokeStyle = 'rgba(2, 132, 199, 0.4)';
                        ctx.lineWidth = 1.5;
                        ctx.setLineDash([3, 3]);
                        ctx.strokeRect(startX + currentRodWidth, rodY, -visualExpansion, rodHeight);
                        ctx.setLineDash([]);
                        ctx.fillStyle = 'rgba(2, 132, 199, 0.08)';
                        ctx.fillRect(startX + currentRodWidth, rodY, -visualExpansion, rodHeight);
                    }
                    // External border for the actual physical rod
                    ctx.strokeStyle = state.colorGradEnd;
                    ctx.lineWidth = 2.5;
                    ctx.strokeRect(startX, rodY, currentRodWidth, rodHeight);
                    ctx.restore();
                    // Microscopic View Zoom Callout Circle
                    const zoomCx = width - 85;
                    const zoomCy = 75;
                    const zoomR = 45;
                    ctx.save();
                    // Draw outer border ring of magnifier
                    ctx.beginPath();
                    ctx.arc(zoomCx, zoomCy, zoomR, 0, Math.PI * 2);
                    ctx.fillStyle = '#ffffff';
                    ctx.fill();
                    ctx.strokeStyle = '#94a3b8';
                    ctx.lineWidth = 3;
                    ctx.stroke();
                    // Microscope glass reflection / grid lines
                    ctx.beginPath();
                    ctx.arc(zoomCx, zoomCy, zoomR, 0, Math.PI * 2);
                    ctx.clip();
                    ctx.fillStyle = '#f8fafc';
                    ctx.fill();
                    // Microscopic grid background
                    ctx.strokeStyle = 'rgba(0,0,0,0.02)';
                    ctx.lineWidth = 1;
                    for (let gx = zoomCx - zoomR; gx < zoomCx + zoomR; gx += 12) {
                        ctx.beginPath();
                        ctx.moveTo(gx, zoomCy - zoomR);
                        ctx.lineTo(gx, zoomCy + zoomR);
                        ctx.stroke();
                    }
                    for (let gy = zoomCy - zoomR; gy < zoomCy + zoomR; gy += 12) {
                        ctx.beginPath();
                        ctx.moveTo(zoomCx - zoomR, gy);
                        ctx.lineTo(zoomCx + zoomR, gy);
                        ctx.stroke();
                    }
                    // Atom lattice visualization inside zoom circle
                    const temperatureInfluence = Math.max((state.t2 + 100) / 100, 0.1);
                    const latticeSpacing = 16 + (deltaT * 0.005);
                    const vibrationAmp = temperatureInfluence * 0.45;
                    ctx.fillStyle = state.colorGradEnd;
                    ctx.strokeStyle = 'rgba(0,0,0,0.12)';
                    ctx.lineWidth = 1;
                    for (let lx = -3; lx <= 3; lx++) {
                        for (let ly = -3; ly <= 3; ly++) {
                            const vx = Math.sin(timestamp * 0.015 + lx) * vibrationAmp;
                            const vy = Math.cos(timestamp * 0.012 + ly) * vibrationAmp;
                            const atomX = zoomCx + lx * latticeSpacing + vx;
                            const atomY = zoomCy + ly * latticeSpacing + vy;
                            // Draw bond connections to right and bottom neighbors
                            if (lx < 3) {
                                const nextAtomX = zoomCx + (lx + 1) * latticeSpacing + Math.sin(timestamp * 0.015 + lx + 1) * vibrationAmp;
                                const nextAtomY = zoomCy + ly * latticeSpacing + Math.cos(timestamp * 0.012 + ly) * vibrationAmp;
                                ctx.beginPath();
                                ctx.moveTo(atomX, atomY);
                                ctx.lineTo(nextAtomX, nextAtomY);
                                ctx.stroke();
                            }
                            if (ly < 3) {
                                const nextAtomX = zoomCx + lx * latticeSpacing + Math.sin(timestamp * 0.015 + lx) * vibrationAmp;
                                const nextAtomY = zoomCy + (ly + 1) * latticeSpacing + Math.cos(timestamp * 0.012 + ly + 1) * vibrationAmp;
                                ctx.beginPath();
                                ctx.moveTo(atomX, atomY);
                                ctx.lineTo(nextAtomX, nextAtomY);
                                ctx.stroke();
                            }
                            // Draw atom node
                            ctx.beginPath();
                            ctx.arc(atomX, atomY, 3.5, 0, Math.PI * 2);
                            ctx.fill();
                        }
                    }
                    // Lens reflection overlay
                    const glassGrad = ctx.createLinearGradient(zoomCx - zoomR, zoomCy - zoomR, zoomCx + zoomR, zoomCy + zoomR);
                    glassGrad.addColorStop(0, 'rgba(255,255,255,0.4)');
                    glassGrad.addColorStop(0.5, 'rgba(255,255,255,0.05)');
                    glassGrad.addColorStop(1, 'rgba(2,132,199,0.05)');
                    ctx.fillStyle = glassGrad;
                    ctx.beginPath();
                    ctx.arc(zoomCx, zoomCy, zoomR, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.restore();
                    // Magnifier link lines from rod end to callout
                    ctx.save();
                    ctx.strokeStyle = 'rgba(148, 163, 184, 0.4)';
                    ctx.lineWidth = 1;
                    ctx.setLineDash([4, 4]);
                    ctx.beginPath();
                    ctx.moveTo(startX + currentRodWidth, rodY);
                    ctx.lineTo(zoomCx - zoomR + 5, zoomCy - 20);
                    ctx.moveTo(startX + currentRodWidth, rodY + rodHeight);
                    ctx.lineTo(zoomCx - zoomR + 5, zoomCy + 20);
                    ctx.stroke();
                    ctx.restore();
                    // Microscope tag text
                    ctx.fillStyle = '#64748b';
                    ctx.font = 'bold 9px sans-serif';
                    ctx.textAlign = 'center';
                    ctx.fillText('미시 원자 격자 뷰', zoomCx, zoomCy + zoomR + 13);
                    // Micro Dial gauge representation below rod right end
                    const gaugeX = startX + currentRodWidth + 10;
                    const gaugeY = rodY + rodHeight / 2;
                    ctx.save();
                    // Draw contact plunger pin pressed against rod end
                    ctx.fillStyle = '#94a3b8';
                    ctx.fillRect(startX + currentRodWidth, gaugeY - 3, 22, 6);
                    ctx.strokeStyle = '#475569';
                    ctx.lineWidth = 1.5;
                    ctx.strokeRect(startX + currentRodWidth, gaugeY - 3, 22, 6);
                    // Dial body
                    const dialR = 24;
                    const dialCx = gaugeX + dialR + 10;
                    const dialCy = gaugeY;
                    ctx.beginPath();
                    ctx.arc(dialCx, dialCy, dialR, 0, Math.PI * 2);
                    ctx.fillStyle = '#ffffff';
                    ctx.fill();
                    ctx.strokeStyle = '#334155';
                    ctx.lineWidth = 2.5;
                    ctx.stroke();
                    // Dial grad ticks
                    ctx.strokeStyle = '#475569';
                    ctx.lineWidth = 1;
                    for (let ti = 0; ti < 12; ti++) {
                        const tickAng = (ti * Math.PI * 2) / 12;
                        ctx.beginPath();
                        ctx.moveTo(dialCx + dialR * Math.cos(tickAng), dialCy + dialR * Math.sin(tickAng));
                        ctx.lineTo(dialCx + (dialR - 4) * Math.cos(tickAng), dialCy + (dialR - 4) * Math.sin(tickAng));
                        ctx.stroke();
                    }
                    // Rotating indicator hand
                    // Rotates 360deg for every 10mm of expansion
                    const handAngle = (deltaL / 10.0) * Math.PI * 2;
                    ctx.strokeStyle = '#ef4444';
                    ctx.lineWidth = 2;
                    ctx.beginPath();
                    ctx.moveTo(dialCx, dialCy);
                    ctx.lineTo(dialCx + (dialR - 6) * Math.cos(handAngle), dialCy + (dialR - 6) * Math.sin(handAngle));
                    ctx.stroke();
                    // Dial hub pin
                    ctx.fillStyle = '#0f172a';
                    ctx.beginPath();
                    ctx.arc(dialCx, dialCy, 3, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.restore();
                    ctx.fillStyle = '#64748b';
                    ctx.font = 'bold 9px sans-serif';
                    ctx.textAlign = 'center';
                    ctx.fillText('마이크로미터 변위계', dialCx, dialCy + dialR + 13);
                    // Visual Temperature Gradient Coloring bar (Repositioned to top-left corner)
                    ctx.save();
                    ctx.font = 'bold 11px Outfit';
                    ctx.fillStyle = '#64748b';
                    ctx.textAlign = 'left';
                    const tempBarX = 24;
                    const tempBarY = 40;
                    const tempBarW = 130;
                    const tempBarH = 6;
                    ctx.fillText(`현재 온도: ${state.t2}°C`, tempBarX, tempBarY - 10);
                    ctx.fillStyle = '#e2e8f0';
                    ctx.fillRect(tempBarX, tempBarY, tempBarW, tempBarH);
                    const barGrad = ctx.createLinearGradient(tempBarX, tempBarY, tempBarX + tempBarW, tempBarY);
                    barGrad.addColorStop(0, '#38bdf8');
                    barGrad.addColorStop(0.5, '#e2e8f0');
                    barGrad.addColorStop(1, '#ef4444');
                    ctx.fillStyle = barGrad;
                    ctx.fillRect(tempBarX, tempBarY, tempBarW, tempBarH);
                    // Draw marker pointer for current temperature T2
                    const normalizedT2 = (state.t2 - (-50)) / 550; // -50 to 500 scale
                    const markerX = tempBarX + Math.min(Math.max(normalizedT2, 0), 1.0) * tempBarW;
                    ctx.fillStyle = '#0f172a';
                    ctx.beginPath();
                    ctx.moveTo(markerX, tempBarY - 2);
                    ctx.lineTo(markerX - 4, tempBarY - 7);
                    ctx.lineTo(markerX + 4, tempBarY - 7);
                    ctx.closePath();
                    ctx.fill();
                    ctx.restore();
                    // Rod Dimensions scale line underneath (L0, Delta L, and Final L)
                    ctx.save();
                    // 1. Vertical guide lines (dashed)
                    ctx.strokeStyle = 'rgba(148, 163, 184, 0.35)';
                    ctx.lineWidth = 1;
                    ctx.setLineDash([3, 3]);
                    // Start guide line (startX)
                    ctx.beginPath();
                    ctx.moveTo(startX, rodY + rodHeight);
                    ctx.lineTo(startX, rodY + rodHeight + 63);
                    ctx.stroke();
                    // Initial length guide line (startX + baseWidth)
                    ctx.beginPath();
                    ctx.moveTo(startX + baseWidth, rodY);
                    ctx.lineTo(startX + baseWidth, rodY + rodHeight + 43);
                    ctx.stroke();
                    // Final end-point guide line (startX + currentRodWidth)
                    ctx.beginPath();
                    ctx.moveTo(startX + currentRodWidth, rodY);
                    ctx.lineTo(startX + currentRodWidth, rodY + rodHeight + 63);
                    ctx.stroke();
                    ctx.setLineDash([]);
                    // 2. Initial Length dimension line (L₀) - Level 1 (dimY1)
                    const dimY1 = rodY + rodHeight + 20;
                    ctx.strokeStyle = '#64748b';
                    ctx.lineWidth = 1;
                    ctx.beginPath();
                    ctx.moveTo(startX, dimY1);
                    ctx.lineTo(startX + baseWidth, dimY1);
                    ctx.stroke();
                    // Arrowheads
                    drawArrowhead(ctx, startX, dimY1, Math.PI);
                    drawArrowhead(ctx, startX + baseWidth, dimY1, 0);
                    // L₀ text label
                    ctx.fillStyle = '#475569';
                    ctx.font = '500 10px Inter';
                    ctx.textAlign = 'center';
                    ctx.fillText(`초기 L₀ = ${state.l0.toFixed(1)} m`, startX + baseWidth / 2, dimY1 - 4);
                    // 3. Changed/Increased Length dimension line (ΔL) - Level 2 (dimY2)
                    if (Math.abs(visualExpansion) > 3) {
                        const dimY2 = rodY + rodHeight + 40;
                        const isExpansion = deltaL >= 0;
                        ctx.strokeStyle = isExpansion ? '#db2777' : '#0284c7';
                        ctx.lineWidth = 1.2;
                        const expStartX = isExpansion ? startX + baseWidth : startX + currentRodWidth;
                        const expEndX = isExpansion ? startX + currentRodWidth : startX + baseWidth;
                        ctx.beginPath();
                        ctx.moveTo(expStartX, dimY2);
                        ctx.lineTo(expEndX, dimY2);
                        ctx.stroke();
                        drawArrowhead(ctx, expStartX, dimY2, Math.PI);
                        drawArrowhead(ctx, expEndX, dimY2, 0);
                        ctx.fillStyle = isExpansion ? '#db2777' : '#0284c7';
                        ctx.font = 'bold 10px Inter';
                        ctx.textAlign = 'center';
                        const sign = isExpansion ? '+' : '';
                        ctx.fillText(`ΔL = ${sign}${deltaL.toFixed(2)} mm`, expStartX + Math.abs(visualExpansion) / 2, dimY2 - 4);
                    }
                    // 4. Total Final Length dimension line (L) - Level 3 (dimY3)
                    const dimY3 = rodY + rodHeight + 60;
                    ctx.strokeStyle = '#334155';
                    ctx.lineWidth = 1.2;
                    ctx.beginPath();
                    ctx.moveTo(startX, dimY3);
                    ctx.lineTo(startX + currentRodWidth, dimY3);
                    ctx.stroke();
                    // vertical ticks
                    ctx.beginPath();
                    ctx.moveTo(startX, dimY3 - 4); ctx.lineTo(startX, dimY3 + 4);
                    ctx.moveTo(startX + currentRodWidth, dimY3 - 4); ctx.lineTo(startX + currentRodWidth, dimY3 + 4);
                    ctx.stroke();
                    // Final L text
                    ctx.fillStyle = '#0f172a';
                    ctx.font = 'bold 11px monospace';
                    ctx.textAlign = 'center';
                    ctx.fillText(`최종 L = ${finalL.toFixed(5)} m`, startX + currentRodWidth / 2, dimY3 + 14);
                    ctx.restore();
                }
                // Event Listeners mapping
                sliderL0.addEventListener('input', syncL0FromSlider);
                inputL0.addEventListener('change', syncL0FromInput);
                sliderT1.addEventListener('input', syncT1FromSlider);
                inputT1.addEventListener('change', syncT1FromInput);
                sliderT2.addEventListener('input', syncT2FromSlider);
                inputT2.addEventListener('change', syncT2FromInput);
                selectMaterial.addEventListener('change', handleMaterialChange);
                presetBtns.forEach(btn => {
                    btn.addEventListener('click', function() {
                        loadPreset(btn.dataset.preset);
                    });
                });
                // Initial run
                handleMaterialChange();
                requestAnimationFrame(animate);
                // Anti-copying / Context protection code
                document.addEventListener('contextmenu', function(e) {
                    e.preventDefault();
                    alert("이 시뮬레이터 프로그램의 지식재산권은 보호받고 있습니다.");
                    return false;
                }, { capture: true });
                document.addEventListener('selectstart', function(e) {
                    e.preventDefault();
                    return false;
                }, { capture: true });
                document.addEventListener('keydown', function(e) {
                    if (e.key === 'F12') {
                        e.preventDefault();
                        alert("이 시뮬레이터 프로그램의 지식재산권은 보호받고 있습니다.");
                        return false;
                    }
                    if (e.ctrlKey) {
                        if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
                            e.preventDefault();
                            alert("이 시뮬레이터 프로그램의 지식재산권은 보호받고 있습니다.");
                            return false;
                        }
                    }
                }, { capture: true });
            }
            // Retry loader sequence
            let loadAttempts = 0;
            function tryLoad() {
                loadAttempts++;
                initSimulator();
                if (!window.__thermalexpansion_initialized) {
                    if (loadAttempts < 50) {
                        setTimeout(tryLoad, 100);
                    }
                }
            }
            if (document.readyState === 'complete' || document.readyState === 'interactive') {
                tryLoad();
            } else {
                document.addEventListener('DOMContentLoaded', tryLoad);
                window.addEventListener('load', tryLoad);
            }
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>재질 선택: 강철, 구리, 알루미늄, 황동 등 분석할 금속을 선택하여 고유 선팽창계수(α)를 적용합니다.</strong></li>
<li style="margin-bottom: 6px;">초기 조건 설정: 봉의 초기 길이(L₀)와 초기 온도(T₁)를 슬라이더 또는 텍스트 입력으로 설정합니다.</li>
<li style="margin-bottom: 6px;">대상 온도 제어: 가열 또는 냉각할 최종 온도(T₂)를 조절하면 봉 아래에 가스 버너 불꽃이나 얼음 결정이 렌더링됩니다.</li>
<li style="margin-bottom: 6px;">실시간 팽창 변위 측정: 정밀 다이얼 게이지와 현미경 뷰를 통해 마이크로미터 및 밀리미터 단위로 미세하게 늘어나고 줄어드는 봉의 길이를 확인합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 선팽창계수 공식 및 재료별 열팽창 특성 해설 보기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 고체 열팽창(Thermal Expansion)의 물리적 근원</h3>
<p>모든 고체 물질은 온도가 상승함에 따라 부피가 팽창하는 성질을 가집니다. 이는 미시적 관점에서 격자 진동(Lattice Vibration)으로 설명됩니다. 고체 내부의 원자들은 원자 간 결합력에 의해 평형 상태의 에너지를 유지하며 진동하고 있습니다. 에너지가 가해져 온도가 올라가면 원자들의 진동 진폭이 커지게 되는데, 원자 간 비선형 포텐셜 에너지 곡선의 비대칭성 때문에 진동 중심 사이의 평균 거리가 멀어지게 됩니다. 이것이 거시적으로 열팽창으로 관찰되는 물리적 원리입니다.</p><ul><li><strong>선팽창 (Linear Expansion):</strong> 막대나 봉과 같이 길이 방향 차원이 지배적인 물체에서 일어나는 팽창입니다.</li><li><strong>체적팽창 (Volume Expansion):</strong> 3차원 입체 형상 전체의 부피가 팽창하는 것으로, 등방성 고체의 경우 체적팽창계수는 선팽창계수의 약 3배(β ≈ 3α)입니다.</li></ul>
<h3>2. 열팽창 설계 방정식과 변위 유도</h3>
<p>고체의 선팽창 관계식은 온도 변화폭이 아주 크지 않은 경우 다음과 같이 선형 근사로 고도로 정밀하게 예측할 수 있습니다.</p><p><strong>① 선팽창 기본 공식:</strong></p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">ΔL = α × L₀ × ΔT &nbsp;[mm]</p><p>여기서 <code>α</code>는 선팽창계수(Coefficient of Linear Expansion, K⁻¹ 또는 °C⁻¹), <code>L₀</code>는 초기 온도에서의 길이(m), <code>ΔT</code>는 온도 변화량(T₂ - T₁, °C)입니다.</p><p><strong>② 최종 길이 계산:</strong></p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">L = L₀ + ΔL = L₀ × (1 + α × ΔT) &nbsp;[m]</p><p><strong>③ 온도 응력 (Thermal Stress):</strong> 만약 양단이 강체 벽으로 구속되어 팽창이 불가능한 상태에서 가열된다면, 팽창하려는 변위만큼 압축 변형률(Strain)이 발생하여 매우 강력한 내력이 발생합니다. 양단 구속 시 발생하는 열응력 공식은 다음과 같습니다:</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.05em; color: #0369a1;">σ_t = E × α × ΔT &nbsp;[MPa]</p><p>여기서 <code>E</code>는 금속의 세로탄성계수(Young's Modulus)입니다. 기계 부품 설계 시 이러한 열응력으로 인한 파손을 방지하기 위해 팽창 여유 갭(Thermal Gap)이나 신축 이음(Expansion Joint) 설치가 필수적입니다.</p>
<h3>3. 주요 금속 재료별 열팽창 특성 및 설계 가이드</h3>
<p>다양한 공업용 금속들은 결정 구조와 결합력의 차이로 인해 상이한 선팽창계수를 가집니다. 설계 시 이종 금속 접합 구조물이 온도 변화를 겪을 때 휠 가능성(바이메탈 효과)을 신중히 고려해야 합니다.</p><ul><li><strong>알루미늄 (Aluminum):</strong> 약 23.0 × 10⁻⁶ /°C 로 열팽창이 매우 크며, 경량화 설계 시 갭 설계가 중요합니다.</li><li><strong>황동 (Brass):</strong> 약 19.0 × 10⁻⁶ /°C 로 동합금 특유의 높은 팽창률을 가집니다.</li><li><strong>구리 (Copper):</strong> 약 17.0 × 10⁻⁶ /°C 로 전선 설계 및 배관 매설 시 길이 방향 수축팽창을 고려해야 합니다.</li><li><strong>탄소강 (Steel):</strong> 약 11.5 × 10⁻⁶ /°C 로 상대적으로 낮고 안정적이며 콘크리트의 팽창계수와 유사하여 철근콘크리트 구조가 성립되는 기반이 됩니다.</li></ul>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/thermal-expansion-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>스프링 처짐 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/spring-deflection-stiffness-calculator-simulator/</link>
					<comments>https://myengnote.com/spring-deflection-stiffness-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Fri, 29 May 2026 00:32:41 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[변형량계산]]></category>
		<category><![CDATA[스프링상수]]></category>
		<category><![CDATA[와알계수]]></category>
		<category><![CDATA[코일스프링]]></category>
		<guid isPermaLink="false">https://myengnote.com/spring-deflection-stiffness-calculator-simulator/</guid>

					<description><![CDATA[소선 지름, 코일 평균 지름, 유효 권수 및 가해진 하중에 따른 코일 스프링의 강성(Stiffness), 처짐량(Deflection), Wahl 보정 응력을 정밀 계산하고 스프링의 실시간 기하학적 압축 상태를 시각화하는 2D 시뮬레이터입니다.]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 스프링 처짐 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for springdeflection-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .springdeflection-calculator-wrapper *, .springdeflection-calculator-wrapper *::before, .springdeflection-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .springdeflection-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7;
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777;
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .springdeflection-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0; left: 0; width: 100%; height: 100%;
            z-index: -1; overflow: hidden; pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: ''; position: absolute; width: 600px; height: 600px; border-radius: 50%; filter: blur(140px); opacity: 0.12;
        }
        .app-background-glow::before { background: var(--color-cyan); top: -10%; right: -5%; animation: pulse-slow 15s infinite alternate; }
        .app-background-glow::after { background: var(--color-purple); bottom: -10%; left: -5%; animation: pulse-slow 20s infinite alternate-reverse; }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.08; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.15; }
        }
        .app-container {
            width: 100%; max-width: 1440px; padding: 24px; display: flex; flex-direction: column; gap: 24px;
        }
        .app-header {
            display: flex; justify-content: space-between; align-items: center; padding: 20px 24px;
            background: var(--color-panel-bg); backdrop-filter: var(--blur-glass); border: 1px solid var(--color-border); border-radius: 16px; box-shadow: var(--shadow-card);
        }
        .logo-area { display: flex; align-items: center; gap: 16px; }
        .logo-icon {
            font-size: 32px; background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta)); -webkit-background-clip: text; -webkit-text-fill-color: transparent;
            display: flex; align-items: center; justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading); font-weight: 800; font-size: 24px; letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-dark)); -webkit-background-clip: text; -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle { font-size: 12px; color: var(--color-text-muted); font-weight: 500; letter-spacing: 0.5px; }
        .header-badge {
            display: flex; align-items: center; gap: 10px; background: rgba(124, 58, 237, 0.1); border: 1px solid rgba(124, 58, 237, 0.2); padding: 6px 14px; border-radius: 20px;
        }
        .pulse-dot {
            width: 8px; height: 8px; background-color: var(--color-purple); border-radius: 50%; box-shadow: 0 0 10px var(--color-purple); animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text { font-size: 11px; font-weight: 600; color: var(--color-purple); letter-spacing: 0.5px; }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel); backdrop-filter: var(--blur-glass); border: 1px solid var(--color-border); border-radius: 20px; padding: 24px; box-shadow: var(--shadow-card);
            display: flex; flex-direction: column; gap: 18px; transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover { border-color: var(--color-border-hover); }
        .panel-header { display: flex; align-items: center; gap: 12px; border-bottom: 1px solid var(--color-border); padding-bottom: 14px; }
        .panel-header i { font-size: 18px; }
        .panel-header h2 { font-family: var(--font-heading); font-size: 18px; font-weight: 600; letter-spacing: 0.5px; }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel { grid-column: 1; }
        .right-column {
            display: flex;
            flex-direction: column;
            gap: 24px;
            min-width: 0;
        }
        .input-group { display: flex; flex-direction: column; gap: 8px; }
        .input-label-row { display: flex; justify-content: space-between; align-items: center; }
        .input-label-row label { font-size: 13px; font-weight: 600; color: var(--color-text-main); display: flex; align-items: center; gap: 8px; }
        .helper-text { font-size: 10px; color: var(--color-text-muted); font-weight: 500; }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within { border-color: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan-glow); }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button, .custom-number-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none; width: 100%; height: 6px; border-radius: 3px; background: rgba(0, 0, 0, 0.05); outline: none; margin: 4px 0; transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; cursor: pointer; transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        .slider-cyan::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 8px var(--color-cyan); }
        .slider-cyan::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-magenta::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 8px var(--color-magenta); }
        .slider-magenta::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-purple::-webkit-slider-thumb { background: var(--color-purple); box-shadow: 0 0 8px var(--color-purple); }
        .slider-purple::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-cyan::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-cyan); }
        .slider-magenta::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-magenta); }
        .slider-purple::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-purple); }
        .select-wrapper { position: relative; display: flex; border-radius: 8px; overflow: hidden; border: 1px solid var(--color-border); background: #ffffff; }
        .custom-select {
            width: 100%; background: #f8fafc; border: none; outline: none; color: #0f172a; padding: 10px 14px; font-family: var(--font-body); font-size: 14px; font-weight: 600; appearance: none; cursor: pointer;
        }
        .select-arrow { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); pointer-events: none; color: var(--color-text-muted); font-size: 12px; }
        .presets-section { display: flex; flex-direction: column; gap: 10px; border-top: 1px solid var(--color-border); padding-top: 16px; }
        .presets-section h3 { font-size: 13px; font-weight: 700; color: var(--color-text-main); display: flex; align-items: center; gap: 8px; }
        .presets-grid { display: flex; flex-direction: column; gap: 8px; }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 10px; padding: 8px 12px; cursor: pointer; color: var(--color-text-main);
            display: flex; align-items: center; gap: 12px; text-align: left; transition: all 0.2s ease;
        }
        .preset-btn:hover { background: rgba(0, 0, 0, 0.04); transform: translateX(4px); }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow)); border-color: var(--color-cyan); box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px; height: 28px; background: rgba(0, 0, 0, 0.02); border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon { background: var(--gradient-primary); color: #fff; }
        .preset-name { font-size: 12px; font-weight: 600; }
        .simulation-panel {
            grid-column: 2;
            align-self: start;
        }
        .canvas-wrapper {
            position: relative; width: 100%; background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%); border: 1px solid rgba(0, 0, 0, 0.06); border-radius: 16px;
            overflow: hidden; display: flex; align-items: center; justify-content: center; 
        }
        #physics-canvas { display: block; width: 100%; height: auto; aspect-ratio: 16 / 10; }
        .canvas-overlay-data { position: absolute; top: 16px; left: 16px; pointer-events: none; display: flex; flex-direction: column; gap: 6px; }
        .overlay-item {
            background: rgba(255, 255, 255, 0.9); color: var(--color-text-main); backdrop-filter: blur(4px); border: 1px solid var(--color-border); padding: 6px 12px; border-radius: 8px;
            display: flex; align-items: center; gap: 8px; font-size: 11px;
        }
        .overlay-item .label { color: var(--color-text-muted); font-weight: 500; }
        .overlay-item .value { font-weight: 700; }
        .simulation-metrics-strip {
            display: flex; background: rgba(0, 0, 0, 0.01); border: 1px solid var(--color-border); border-radius: 12px; padding: 12px 20px;
            justify-content: space-around; align-items: center; gap: 10px; margin-top: 10px;
        }
        .mini-metric { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; }
        .mini-metric .label { font-size: 10px; font-weight: 600; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
        .mini-metric .value { font-size: 14px; font-weight: 700; color: var(--color-text-main); font-family: var(--font-heading); }
        .mini-divider { width: 1px; height: 24px; background: var(--color-border); }
        .results-panel { }
        .ratio-readout-box {
            background: linear-gradient(135deg, var(--color-cyan-glow) 0%, var(--color-purple-glow) 100%); border: 1px solid rgba(2, 132, 199, 0.15); border-radius: 16px;
            padding: 20px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 6px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02);
        }
        .ratio-title { font-size: 11px; font-weight: 700; color: var(--color-cyan); letter-spacing: 1px; text-transform: uppercase; }
        .ratio-value {
            font-family: var(--font-heading); font-weight: 800; font-size: 24px; background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text; -webkit-text-fill-color: transparent;
        }
        .ratio-type { font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
        .results-grid { display: flex; flex-direction: column; gap: 12px; }
        .result-card {
            background: rgba(255, 255, 255, 0.85); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03); border: 1px solid var(--color-border); border-radius: 12px;
            padding: 12px 16px; display: flex; align-items: center; gap: 16px; transition: all 0.2s ease;
        }
        .result-card:hover { transform: translateY(-2px); border-color: var(--color-cyan); background: var(--color-cyan-glow); }
        .card-icon {
            width: 38px; height: 38px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 10px;
            display: flex; align-items: center; justify-content: center; font-size: 14px; color: var(--color-text-muted);
        }
        .result-card:hover .card-icon { color: var(--color-cyan); border-color: var(--color-cyan); background: var(--color-cyan-glow); }
        .card-content { display: flex; flex-direction: column; gap: 2px; }
        .card-unit { font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
        .card-value { font-family: var(--font-heading); font-weight: 700; font-size: 17px; color: var(--color-text-main); }
        .formula-card {
            background: #ffffff; border: 1px solid var(--color-border); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 8px; font-size: 12px;
        }
        .formula-card h4 { font-weight: 700; color: var(--color-text-main); }
        .formula-equation {
            font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace; color: #0284c7; font-size: 13px; background: #f8fafc; border-color: var(--color-border);
            padding: 8px 10px; border-radius: 6px;
        }
        /* Container Query for Responsiveness inside WP */
        @container springdeflection-container (max-width: 1024px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.springdeflection-calculator-wrapper .app-main-grid,
.springdeflection-calculator-wrapper .main-grid,
.springdeflection-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.springdeflection-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.springdeflection-calculator-wrapper .simulation-panel,
.springdeflection-calculator-wrapper .canvas-panel,
.springdeflection-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.springdeflection-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.springdeflection-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.springdeflection-calculator-wrapper .simulation-results-section .ratio-readout-box,
.springdeflection-calculator-wrapper .simulation-results-section .re-readout-box,
.springdeflection-calculator-wrapper .simulation-results-section .status-readout-box,
.springdeflection-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.springdeflection-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.springdeflection-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.springdeflection-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .springdeflection-calculator-wrapper .app-main-grid,
    .springdeflection-calculator-wrapper .main-grid,
    .springdeflection-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .springdeflection-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .springdeflection-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .springdeflection-calculator-wrapper .simulation-panel,
    .springdeflection-calculator-wrapper .canvas-panel,
    .springdeflection-calculator-wrapper .sim-panel,
    .springdeflection-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .springdeflection-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .springdeflection-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .springdeflection-calculator-wrapper .simulation-results-section .re-readout-box,
    .springdeflection-calculator-wrapper .simulation-results-section .status-readout-box,
    .springdeflection-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .springdeflection-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .springdeflection-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.springdeflection-calculator-wrapper .app-container,
.springdeflection-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.springdeflection-calculator-wrapper .simulation-results-section .formula-card,
.springdeflection-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 8px !important;
}
.springdeflection-calculator-wrapper .simulation-results-section .formula-card h4,
.springdeflection-calculator-wrapper .results-panel .formula-card h4 {
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
}
.springdeflection-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="springdeflection-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-wave-square"></i></div>
                <div>
                    <h1>SPRING DEFLECTION</h1>
                    <div class="subtitle">코일 스프링 처짐량 계산기 및 실시간 2D 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">SPRING PHYSICS ACTIVE</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>스프링 인자 제어</h2>
                </div>
                <!-- Material select -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="select-material"><i class="fa-solid fa-atom text-cyan"></i> 스프링 재료 (G)</label>
                    </div>
                    <div class="select-wrapper">
                        <select id="select-material" class="custom-select">
                            <option value="79.3" selected>탄소 스프링강 (G = 79.3 GPa)</option>
                            <option value="69.0">스테인리스강 (G = 69.0 GPa)</option>
                            <option value="78.5">크롬 바나듐강 (G = 78.5 GPa)</option>
                            <option value="41.0">인청동 (G = 41.0 GPa)</option>
                        </select>
                        <i class="fa-solid fa-chevron-down select-arrow"></i>
                    </div>
                </div>
                <!-- Wire diameter d -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-d"><i class="fa-solid fa-circle text-magenta"></i> 소선 지름 (d)</label>
                        <span class="helper-text">(0.5 ~ 20.0 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-d" class="custom-number-input" min="0.5" max="20.0" value="4.0" step="any">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-d" class="custom-slider slider-magenta" min="5" max="200" value="40">
                </div>
                <!-- Mean diameter D -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-mean-d"><i class="fa-solid fa-circle-notch text-cyan"></i> 코일 평균 지름 (D)</label>
                        <span class="helper-text">(5.0 ~ 200.0 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-mean-d" class="custom-number-input" min="5" max="200" value="30.0" step="any">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-mean-d" class="custom-slider slider-cyan" min="50" max="2000" value="300">
                </div>
                <!-- Active Coils n -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-n"><i class="fa-solid fa-calculator text-purple"></i> 유효 감김수 (n)</label>
                        <span class="helper-text">(2 ~ 30 회)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-n" class="custom-number-input" min="2" max="30" value="8" step="any">
                        <div class="unit-badge">회</div>
                    </div>
                    <input type="range" id="slider-n" class="custom-slider slider-purple" min="2" max="30" value="8">
                </div>
                <!-- Load Force F -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-force"><i class="fa-solid fa-weight-hanging text-magenta"></i> 인가 압축 하중 (F)</label>
                        <span class="helper-text">(0 ~ 2000 N)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-force" class="custom-number-input" min="0" max="2000" value="250" step="any">
                        <div class="unit-badge">N</div>
                    </div>
                    <input type="range" id="slider-force" class="custom-slider slider-magenta" min="0" max="2000" value="250">
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 용도별 스프링 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn active" id="preset-auto">
                            <div class="preset-icon"><i class="fa-solid fa-car"></i></div>
                            <div class="preset-details"><span class="preset-name">차량 서스펜션</span><span class="preset-spec">고강성 대형 스프링</span></div>
                        </button>
                        <button class="preset-btn" id="preset-valve">
                            <div class="preset-icon"><i class="fa-solid fa-gear"></i></div>
                            <div class="preset-details"><span class="preset-name">엔진 흡배기 밸브</span><span class="preset-spec">고밀도 정밀 강성</span></div>
                        </button>
                        <button class="preset-btn" id="preset-pen">
                            <div class="preset-icon"><i class="fa-solid fa-pen"></i></div>
                            <div class="preset-details"><span class="preset-name">볼펜 스프링</span><span class="preset-spec">초미세 경량 와이어</span></div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <i class="fa-solid fa-dharmachakra text-magenta"></i>
                                    <h2>스프링 실시간 압축 거동 및 응력 집중 분석</h2>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas" width="640" height="400"></canvas>
                                    <div class="canvas-overlay-data">
                                        <div class="overlay-item">
                                            <span class="label">운전 상태:</span>
                                            <span class="value" id="overlay-run-status">정상 탄성 변형 중</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <span class="label">스프링 지수 (C)</span>
                                        <span class="value" id="val-index">7.50</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label">밀착 높이 (Solid Height)</span>
                                        <span class="value" id="val-solid-height">40.0 mm</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label">Wahl 응력 보정 계수 (Kw)</span>
                                        <span class="value" id="val-wahl">1.20</span>
                                    </div>
                                </div>
                            <!-- Integrated Results Analysis Section -->
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">계산된 탄성 처짐량 (&delta;)</div>
                                    <div class="ratio-value" id="txt-deflection">12.50 mm</div>
                                    <div class="ratio-type" id="txt-stiffness">스프링 상수: 20.0 N/mm</div>
                                </div>
                                <div class="results-grid">
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-shield-halved text-success"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">스프링 상수 (Stiffness)</span>
                                            <span class="card-value" id="res-stiffness">20.06 N/mm</span>
                                        </div>
                                    </div>
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-triangle-exclamation"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">Wahl 보정 전단 응력 (&tau;)</span>
                                            <span class="card-value" id="res-stress">143 MPa</span>
                                        </div>
                                    </div>
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-heart-circle-check"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">전단 항복 안전 여유 (Sf)</span>
                                            <span class="card-value" id="res-safety">4.20</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-info-circle text-cyan"></i> 스프링 거동 설계 관계식</h4>
                                    <div class="formula-equation">
                                        k = (G × d^4) / (8 × D^3 × n)
                                    </div>
                                    <div class="formula-equation">
                                        &tau; = Kw × (8 × F × D) / (&pi; × d^3)
                                    </div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- CORE INTERACTIVE ENGINE -->
    </div>
</div>
<script>
    // Polyfill for CanvasRenderingContext2D.roundRect for backward compatibility
    if (typeof CanvasRenderingContext2D !== 'undefined') {
        if (!CanvasRenderingContext2D.prototype.roundRect) {
        CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {
            if (typeof r === 'number') r = [r];
            if (!Array.isArray(r)) r = [0];
            const rad = r[0] || 0;
            this.beginPath();
            this.moveTo(x + rad, y);
            this.lineTo(x + w - rad, y);
            this.quadraticCurveTo(x + w, y, x + w, y + rad);
            this.lineTo(x + w, y + h - rad);
            this.quadraticCurveTo(x + w, y + h, x + w - rad, y + h);
            this.lineTo(x + rad, y + h);
            this.quadraticCurveTo(x, y + h, x, y + h - rad);
            this.lineTo(x, y + rad);
            this.quadraticCurveTo(x, y, x + rad, y);
            this.closePath();
            return this;
        };
      }
    }
        (function() {
            if (window.__springdeflection_initialized) return;
            window.__springdeflection_initialized = true;
            const selectMaterial = document.getElementById('select-material');
            const inputD = document.getElementById('input-d');
            const sliderD = document.getElementById('slider-d');
            const inputMeanD = document.getElementById('input-mean-d');
            const sliderMeanD = document.getElementById('slider-mean-d');
            const inputN = document.getElementById('input-n');
            const sliderN = document.getElementById('slider-n');
            const inputForce = document.getElementById('input-force');
            const sliderForce = document.getElementById('slider-force');
            const txtDeflection = document.getElementById('txt-deflection');
            const txtStiffness = document.getElementById('txt-stiffness');
            const valIndex = document.getElementById('val-index');
            const valSolidHeight = document.getElementById('val-solid-height');
            const valWahl = document.getElementById('val-wahl');
            const resStiffness = document.getElementById('res-stiffness');
            const resStress = document.getElementById('res-stress');
            const resSafety = document.getElementById('res-safety');
            const overlayRunStatus = document.getElementById('overlay-run-status');
            const state = {
                g: 79.3, // GPa
                d: 4.0,  // mm
                D: 30.0, // mm
                n: 8,    // active coils
                force: 250.0, // N
                deflection: 0.0,
                stiffness: 0.0,
                stress: 0.0,
                safety: 0.0,
                isSolidLock: false
            };
            const ranges = {
                d: { min: 0.5, max: 20.0 },
                D: { min: 5.0, max: 200.0 },
                n: { min: 2.0, max: 30.0 },
                force: { min: 0.0, max: 2000.0 }
            };
            function calculateSpring() {
                // Ensure mean diameter is larger than wire diameter to avoid impossible geometry
                if (state.D < state.d + 1.0) {
                    state.D = state.d + 1.0;
                    inputMeanD.value = state.D.toFixed(1);
                    sliderMeanD.value = Math.round(state.D * 10);
                }
                const G_MPa = state.g * 1000.0;
                // Spring constant: k = (G * d^4) / (8 * D^3 * n)
                const d4 = Math.pow(state.d, 4);
                const D3 = Math.pow(state.D, 3);
                const k = (G_MPa * d4) / (8.0 * D3 * state.n);
                state.stiffness = k;
                // Total coils (squared and ground ends has 2 inactive coils)
                const totalCoils = state.n + 2;
                const solidHeight = totalCoils * state.d;
                state.solidHeight = solidHeight;
                // Free Height
                // Make it dynamic: solid height + 60mm so we always have compression room
                const freeHeight = solidHeight + 60.0;
                state.freeHeight = freeHeight;
                // Theoretical deflection
                let def = state.force / k;
                // Real physical boundary: cannot compress beyond solid height
                const maxDef = freeHeight - solidHeight - 1.5;
                state.isSolidLock = false;
                if (def > maxDef) {
                    def = maxDef;
                    state.isSolidLock = true;
                }
                state.deflection = def;
                // Spring Index C
                let C = state.D / state.d;
                if (C < 1.1) { C = 1.1; }
                state.springIndex = C;
                // Wahl Correction factor Kw
                const Kw = ((4.0 * C - 1.0) / (4.0 * C - 4.0)) + (0.615 / C);
                state.wahlFactor = Kw;
                // Shear stress
                // To display true stress when spring is bottomed out, compute force at solid height
                const actualForce = state.isSolidLock ? (maxDef * k) : state.force;
                const stress = Kw * (8.0 * actualForce * state.D) / (Math.PI * Math.pow(state.d, 3));
                state.stress = stress;
                // Safety factor against shear yield (assume yield stress is 600 MPa)
                const yieldStress = 600.0;
                state.safety = yieldStress / stress;
                updateUIValues();
            }
            function syncDFromInput() {
                let val = parseFloat(inputD.value);
                if (isNaN(val)) { val = ranges.d.min; }
                if (val < ranges.d.min) { val = ranges.d.min; }
                if (val > ranges.d.max) { val = ranges.d.max; }
                state.d = val;
                inputD.value = val.toFixed(1);
                sliderD.value = Math.round(val * 10);
                calculateSpring();
            }
            function syncDFromSlider() {
                state.d = parseFloat(sliderD.value) / 10;
                inputD.value = state.d.toFixed(1);
                calculateSpring();
            }
            function syncMeanDFromInput() {
                let val = parseFloat(inputMeanD.value);
                if (isNaN(val)) { val = ranges.D.min; }
                if (val < ranges.D.min) { val = ranges.D.min; }
                if (val > ranges.D.max) { val = ranges.D.max; }
                state.D = val;
                inputMeanD.value = val.toFixed(1);
                sliderMeanD.value = Math.round(val * 10);
                calculateSpring();
            }
            function syncMeanDFromSlider() {
                state.D = parseFloat(sliderMeanD.value) / 10;
                inputMeanD.value = state.D.toFixed(1);
                calculateSpring();
            }
            function syncNFromInput() {
                let val = parseFloat(inputN.value);
                if (isNaN(val)) { val = ranges.n.min; }
                if (val < ranges.n.min) { val = ranges.n.min; }
                if (val > ranges.n.max) { val = ranges.n.max; }
                state.n = val;
                inputN.value = val.toFixed(1);
                sliderN.value = Math.round(val);
                calculateSpring();
            }
            function syncNFromSlider() {
                state.n = parseFloat(sliderN.value);
                inputN.value = state.n.toFixed(0);
                calculateSpring();
            }
            function syncForceFromInput() {
                let val = parseFloat(inputForce.value);
                if (isNaN(val)) { val = ranges.force.min; }
                if (val < ranges.force.min) { val = ranges.force.min; }
                if (val > ranges.force.max) { val = ranges.force.max; }
                state.force = val;
                inputForce.value = val.toFixed(0);
                sliderForce.value = Math.round(val);
                calculateSpring();
            }
            function syncForceFromSlider() {
                state.force = parseFloat(sliderForce.value);
                inputForce.value = state.force.toFixed(0);
                calculateSpring();
            }
            function updateUIValues() {
                txtDeflection.innerText = state.deflection.toFixed(2) + ' mm';
                txtStiffness.innerText = '스프링 상수: ' + state.stiffness.toFixed(2) + ' N/mm';
                valIndex.innerText = state.springIndex.toFixed(2);
                valSolidHeight.innerText = state.solidHeight.toFixed(1) + ' mm';
                valWahl.innerText = state.wahlFactor.toFixed(3);
                resStiffness.innerText = state.stiffness.toFixed(2) + ' N/mm';
                resStress.innerText = state.stress.toFixed(0) + ' MPa';
                if (state.safety > 10.0) {
                    resSafety.innerText = '10.0+';
                } else {
                    resSafety.innerText = state.safety.toFixed(2);
                }
                if (state.isSolidLock) {
                    overlayRunStatus.innerText = '코일 밀착 상태 (밀착 차단 경보!)';
                    overlayRunStatus.style.color = '#db2777';
                } else {
                    if (state.stress > 600.0) {
                        overlayRunStatus.innerText = '항복 도달 (영구적 소성 처짐 발생)';
                        overlayRunStatus.style.color = '#db2777';
                    } else {
                        if (state.safety < 1.5) {
                            overlayRunStatus.innerText = '위험 (고응력 반복 피로 주의)';
                            overlayRunStatus.style.color = '#f59e0b';
                        } else {
                            overlayRunStatus.innerText = '안전 (적정 탄성 작동 중)';
                            overlayRunStatus.style.color = '#10b981';
                        }
                    }
                }
            }
            // Material bindings
            selectMaterial.addEventListener('change', function() {
                state.g = parseFloat(selectMaterial.value);
                calculateSpring();
            });
            inputD.addEventListener('change', syncDFromInput);
            sliderD.addEventListener('input', syncDFromSlider);
            inputMeanD.addEventListener('change', syncMeanDFromInput);
            sliderMeanD.addEventListener('input', syncMeanDFromSlider);
            inputN.addEventListener('change', syncNFromInput);
            sliderN.addEventListener('input', syncNFromSlider);
            inputForce.addEventListener('change', syncForceFromInput);
            sliderForce.addEventListener('input', syncForceFromSlider);
            // Presets
            document.getElementById('preset-auto').addEventListener('click', function() {
                setActivePreset('preset-auto');
                state.g = 79.3;
                state.d = 12.0;
                state.D = 110.0;
                state.n = 6;
                state.force = 1200;
                syncControlsToState();
                calculateSpring();
            });
            document.getElementById('preset-valve').addEventListener('click', function() {
                setActivePreset('preset-valve');
                state.g = 78.5;
                state.d = 3.5;
                state.D = 24.0;
                state.n = 8;
                state.force = 320;
                syncControlsToState();
                calculateSpring();
            });
            document.getElementById('preset-pen').addEventListener('click', function() {
                setActivePreset('preset-pen');
                state.g = 69.0;
                state.d = 0.6;
                state.D = 4.8;
                state.n = 15;
                state.force = 4;
                syncControlsToState();
                calculateSpring();
            });
            function setActivePreset(id) {
                document.getElementById('preset-auto').classList.remove('active');
                document.getElementById('preset-valve').classList.remove('active');
                document.getElementById('preset-pen').classList.remove('active');
                document.getElementById(id).classList.add('active');
            }
            function syncControlsToState() {
                selectMaterial.value = state.g.toFixed(1);
                inputD.value = state.d.toFixed(1);
                sliderD.value = Math.round(state.d * 10);
                inputMeanD.value = state.D.toFixed(1);
                sliderMeanD.value = Math.round(state.D * 10);
                inputN.value = state.n.toFixed(0);
                sliderN.value = Math.round(state.n);
                inputForce.value = state.force.toFixed(0);
                sliderForce.value = Math.round(state.force);
            }
            // Canvas drawing
            const canvas = document.getElementById('physics-canvas');
            const ctx = canvas.getContext('2d');
            function getDPR() { return window.devicePixelRatio || 1; }
            function initCanvas() {
                const dpr = getDPR();
                const rect = canvas.getBoundingClientRect();
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            window.addEventListener('resize', initCanvas);
            initCanvas();
            function animate(currentTime) {
                const dpr = getDPR();
                const width = canvas.width / dpr;
                const height = canvas.height / dpr;
                ctx.clearRect(0, 0, width, height);
                // Grid
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.05)';
                ctx.lineWidth = 1;
                const gridSize = 25;
                for (let x = 0; x < width; x += gridSize) {
                    ctx.beginPath();
                    ctx.moveTo(x, 0);
                    ctx.lineTo(x, height);
                    ctx.stroke();
                }
                for (let y = 0; y < height; y += gridSize) {
                    ctx.beginPath();
                    ctx.moveTo(0, y);
                    ctx.lineTo(width, y);
                    ctx.stroke();
                }
                const cx = width / 2;
                const cy = height / 2 + 15;
                // Scale factor based on standard width 640px
                const S = width / 640;
                // Dynamic auto-zoom: scale spring to fill canvas properly
                const availH = height * 0.62; // use 62% of canvas height for spring
                const drawHeight = Math.max(80, availH);
                const activeCoils = state.n;
                const totalCoils = activeCoils + 2;
                // Current compressed height ratio
                const ratioHeight = (state.freeHeight - state.deflection) / state.freeHeight;
                const currentHeight = drawHeight * ratioHeight;
                const startY = cy - drawHeight / 2;
                const endY = startY + currentHeight;
                // Dynamic diameter: normalize to canvas width (fills ~35% of width)
                const maxDWidth = Math.min(width * 0.35, 160);
                const drawD = (40.0 + (state.D / 200.0) * (maxDWidth - 40.0)) * S;
                // Wire width visual scaling
                const drawWire = Math.min(Math.max(state.d * 1.5 * S, 2.5), 22 * S);
                // Draw Top Support Plate
                ctx.save();
                ctx.fillStyle = '#cbd5e1';
                ctx.strokeStyle = '#475569';
                ctx.lineWidth = 3 * S;
                ctx.beginPath();
                ctx.roundRect(cx - drawD / 2 - 25 * S, startY - 14 * S, drawD + 50 * S, 14 * S, 2 * S);
                ctx.fill();
                ctx.stroke();
                ctx.restore();
                // Draw Bottom Moving Plate (which pushes or hangs)
                ctx.save();
                ctx.fillStyle = '#94a3b8';
                ctx.strokeStyle = '#334155';
                ctx.lineWidth = 3 * S;
                ctx.beginPath();
                ctx.roundRect(cx - drawD / 2 - 20 * S, endY, drawD + 40 * S, 14 * S, 2 * S);
                ctx.fill();
                ctx.stroke();
                ctx.restore();
                // Draw Helix Coil Spring (Beautiful 3D representation)
                ctx.save();
                ctx.lineJoin = 'round';
                ctx.lineCap = 'round';
                ctx.lineWidth = drawWire;
                // Determine stress factor for segment coloring (grey -> magenta glow)
                const yldStr = 600.0;
                const stressFactor = Math.min(state.stress / yldStr, 1.2);
                let springColor = '#64748b';
                if (stressFactor > 0.05) {
                    const r = Math.round(100 + (219 - 100) * Math.min(stressFactor, 1));
                    const g = Math.round(116 + (39 - 116) * Math.min(stressFactor, 1));
                    const b = Math.round(139 + (119 - 139) * Math.min(stressFactor, 1));
                    springColor = 'rgb(' + r + ',' + g + ',' + b + ')';
                }
                ctx.strokeStyle = springColor;
                if (stressFactor > 0.85) {
                    ctx.shadowBlur = 10 * S;
                    ctx.shadowColor = '#db2777';
                }
                // Parametric helix curve
                ctx.beginPath();
                const segments = totalCoils * 24;
                const stepY = currentHeight / segments;
                const stepAngle = (totalCoils * Math.PI * 2) / segments;
                for (let i = 0; i <= segments; i++) {
                    const angle = i * stepAngle;
                    const x = cx + Math.cos(angle) * (drawD / 2);
                    const y = startY + i * stepY;
                    if (i === 0) {
                        ctx.moveTo(x, y);
                    } else {
                        ctx.lineTo(x, y);
                    }
                }
                ctx.stroke();
                ctx.restore();
                // Draw Force Arrow (Magenta, pushing down)
                if (state.force > 0.0) {
                    ctx.save();
                    ctx.strokeStyle = '#db2777';
                    ctx.fillStyle = '#db2777';
                    ctx.lineWidth = Math.min(state.force * 0.005 + 2, 7) * S;
                    ctx.shadowBlur = 8 * S;
                    ctx.shadowColor = '#db2777';
                    // Draw vertical arrow above top plate pushing down
                    const arrowY = startY - 70 * S;
                    ctx.beginPath();
                    ctx.moveTo(cx, arrowY);
                    ctx.lineTo(cx, startY - 20 * S);
                    ctx.stroke();
                    // Arrowhead
                    ctx.beginPath();
                    ctx.moveTo(cx, startY - 17 * S);
                    ctx.lineTo(cx - 8 * S, startY - 28 * S);
                    ctx.lineTo(cx + 8 * S, startY - 28 * S);
                    ctx.closePath();
                    ctx.fill();
                    // Label text
                    ctx.fillStyle = '#db2777';
                    ctx.font = 'bold ' + Math.max(9, 11 * S) + 'px Inter';
                    ctx.textAlign = 'center';
                    ctx.fillText('Load F = ' + state.force.toFixed(0) + ' N', cx, arrowY - 8 * S);
                    ctx.restore();
                }
                // Draw deflection indicator dimension lines
                ctx.save();
                ctx.strokeStyle = '#0284c7';
                ctx.lineWidth = 1.5 * S;
                ctx.fillStyle = '#0284c7';
                ctx.font = 'bold ' + Math.max(8.5, 10 * S) + 'px Inter';
                ctx.textAlign = 'left';
                // Top extension line
                ctx.beginPath();
                ctx.moveTo(cx + drawD / 2 + 30 * S, startY);
                ctx.lineTo(cx + drawD / 2 + 75 * S, startY);
                ctx.stroke();
                // Current bottom extension line
                ctx.beginPath();
                ctx.moveTo(cx + drawD / 2 + 25 * S, endY);
                ctx.lineTo(cx + drawD / 2 + 75 * S, endY);
                ctx.stroke();
                // Dimension line arrows
                ctx.beginPath();
                ctx.moveTo(cx + drawD / 2 + 65 * S, startY);
                ctx.lineTo(cx + drawD / 2 + 65 * S, endY);
                ctx.stroke();
                // Arrowheads
                ctx.beginPath();
                ctx.moveTo(cx + drawD / 2 + 65 * S, startY);
                ctx.lineTo(cx + drawD / 2 + 62 * S, startY + 6 * S);
                ctx.lineTo(cx + drawD / 2 + 68 * S, startY + 6 * S);
                ctx.closePath();
                ctx.fill();
                ctx.beginPath();
                ctx.moveTo(cx + drawD / 2 + 65 * S, endY);
                ctx.lineTo(cx + drawD / 2 + 62 * S, endY - 6 * S);
                ctx.lineTo(cx + drawD / 2 + 68 * S, endY - 6 * S);
                ctx.closePath();
                ctx.fill();
                // Text
                ctx.fillText('Height = ' + (state.freeHeight - state.deflection).toFixed(1) + ' mm', cx + drawD / 2 + 80 * S, cy);
                ctx.restore();
                requestAnimationFrame(animate);
            }
            requestAnimationFrame(animate);
            // Initial calculation
            calculateSpring();
            // Right click / Copy Protection
            (function() {
                function blockEvents() {
                    document.addEventListener('contextmenu', function(e) {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }, { capture: true });
                    document.addEventListener('selectstart', function(e) {
                        e.preventDefault();
                        return false;
                    }, { capture: true });
                }
                if (document.readyState === 'complete' || document.readyState === 'interactive') {
                    blockEvents();
                } else {
                    document.addEventListener('DOMContentLoaded', blockEvents);
                }
            })();
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>재료 물성 선택: 탄소강, 스테인리스강, 인청동 등 스프링 소재를 선택하여 전단 탄성 계수(G)를 지정합니다.</strong></li>
<li style="margin-bottom: 6px;">기하학적 변수 지정: 스프링 소선 지름(d), 코일 평균 지름(D), 유효 권수(n) 슬라이더를 부품 카탈로그 스펙에 맞춰 제어합니다.</li>
<li style="margin-bottom: 6px;">인가 하중 설정: 스프링에 가하는 외부 힘(F)을 조절하여 압축 하중을 작용시킵니다.</li>
<li style="margin-bottom: 6px;">실시간 압축 변형 관찰: 2D 시뮬레이터 속 스프링이 탄성 공식에 맞춰 실시간으로 압축되며, 전단 응력 부하에 비례하여 헬릭스 코일이 붉은색(Magenta Glow)으로 변하는 시각적 피드백을 확인합니다.</li>
<li style="margin-bottom: 6px;">밀착 상태 및 파손 위험 검토: 스프링이 완전히 닫히는 밀착 높이(Solid Height)에 도달했는지 확인하고, 안전 계수를 통해 전단 항복 강도 이하로 안전하게 운전되고 있는지 최종 판정합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 기계공학 해설 및 스프링 설계 규격 (KS/ISO) 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 헬리컬 코일 스프링(Helical Spring)의 강성 공식 유도</h3>
<p>코일 스프링은 선재(Wire)를 나선형으로 감아 비틀림 탄성 변형(Torsional Deflection)을 이용하여 에너지를 저장하고 완충 작용을 하는 대표적인 탄성 기계 기구 요소입니다. 스프링에 압축 하중 <code>F</code>가 가해지면 소선 단면에는 비틀림 모멘트 <code>T = F &middot; D / 2</code>가 균일하게 작용합니다.</p><p>비틀림 변형 에너지를 적분하여 유도되는 코일 스프링의 **스프링 상수(Stiffness / Spring Rate, k)**는 다음과 같이 정의됩니다:</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">k = (G &middot; d<sup>4</sup>) / (8 &middot; D<sup>3</sup> &middot; n) &nbsp;[N/mm]</p><p>여기서 기하 인자들은 다음과 같습니다:</p><ul><li><strong>G: 재료의 전단 탄성 계수 (Shear Modulus, GPa)</strong> &#8211; 철강 소재는 약 79.3 GPa, 스테인리스강은 69 GPa 내외입니다.</li><li><strong>d: 소선의 지름 (Wire Diameter, mm)</strong> &#8211; 힘의 4제곱에 비례하여 스프링의 강성에 지대한 영향을 미칩니다.</li><li><strong>D: 코일 평균 지름 (Mean Coil Diameter, mm)</strong> &#8211; 코일 외경(D<sub>o</sub>)에서 소선 지름(d)을 뺀 치수입니다.</li><li><strong>n: 유효 권수 (Active Coils)</strong> &#8211; 변형에 실제로 참여하는 감김 횟수입니다.</li></ul>
<h3>2. Wahl 보정 계수를 반영한 전단 응력 해석</h3>
<p>스프링 소선 내부에는 단순 비틀림 응력 외에도 소선이 구부러짐으로써 발생하는 직접 전단 응력과 곡률(Curvature)에 의한 응력 집중 현상이 내측 궤도에 강하게 발생합니다. 기계공학자 <em>A. M. Wahl</em>은 이를 보정하기 위해 다음과 같은 <strong>와알 보정 계수 (Wahl Correction Factor, K<sub>W</sub>)</strong>를 제안했습니다:</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">K<sub>W</sub> = (4C &#8211; 1)/(4C &#8211; 4) + 0.615/C &nbsp;&nbsp;(여기서 스프링 지수 C = D / d)</p><p>이를 반영한 볼트 소선의 최대 전단 응력 <code>&tau;</code>는 다음과 같이 계산되며, 이 응력이 스프링 재료의 전단 항복 한계 이하에 머물러야 소성 처짐(Set)이 생기지 않습니다:</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.1em; color: #0369a1;">&tau; = K<sub>W</sub> &times; (8 &middot; F &middot; D) / (&pi; &middot; d<sup>3</sup>) &nbsp;[MPa]</p>
<h3>3. 스프링 고유 한계점 및 밀착 차단 (Solid Height)</h3>
<p>스프링이 과도하게 하중을 받으면 코일 소선들이 서로 맞닿는 상태가 되는데, 이 한계 상태의 높이를 <strong>밀착 높이 (Solid Height, h<sub>s</sub>)</strong>라고 합니다. 밀착 조건 하에서는 추가적인 탄성 처짐이 불가능하며 시스템이 딱딱한 강체(Solid Block)로 작동하여 막대한 충격력이 나사면과 프레임에 고스란히 전달됩니다. 따라서 일반 설계 시 최대 작동 변위는 밀착 변형량 대비 80%를 넘지 않도록 제한 안전 여유를 설계 규격(KS B 2400)에서 권장하고 있습니다.</p>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/spring-deflection-stiffness-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>베어링 수명 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/bearing-life-calculator-simulator/</link>
					<comments>https://myengnote.com/bearing-life-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Thu, 28 May 2026 14:24:13 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[ISO281]]></category>
		<category><![CDATA[L10수명]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[동당량하중]]></category>
		<category><![CDATA[베어링수명]]></category>
		<guid isPermaLink="false">https://myengnote.com/bearing-life-calculator-simulator/</guid>

					<description><![CDATA[ISO 281 규격에 의거하여 볼/롤러 베어링의 동당량 하중과 정격 수명(L10h)을 계산하고, 부하 벡터에 따른 궤도면 접촉 응력 분포와 윤활 유동을 시각화하는 초정밀 2D 시뮬레이터입니다.]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 베어링 수명 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for bearinglife-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .bearinglife-calculator-wrapper *, .bearinglife-calculator-wrapper *::before, .bearinglife-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .bearinglife-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7;
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777;
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --color-warning: #f59e0b;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .bearinglife-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.12;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.08; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.15; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-dark));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(2, 132, 199, 0.1);
            border: 1px solid rgba(2, 132, 199, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-cyan);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-cyan);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-cyan);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .right-column {
            display: flex;
            flex-direction: column;
            gap: 24px;
            min-width: 0;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: var(--color-cyan); }
        .text-magenta { color: var(--color-magenta); }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .mode-select-container {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .mode-label {
            font-size: 12px;
            font-weight: 700;
            color: var(--color-text-muted);
            letter-spacing: 0.5px;
        }
        .segmented-control {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            background: rgba(0, 0, 0, 0.03);
            border: 1px solid var(--color-border);
            padding: 4px;
            border-radius: 12px;
            gap: 4px;
        }
        .segmented-btn {
            background: transparent;
            border: none;
            color: var(--color-text-muted);
            padding: 8px 4px;
            border-radius: 8px;
            font-size: 11px;
            font-weight: 700;
            cursor: pointer;
            transition: all 0.2s ease;
            text-align: center;
        }
        .segmented-btn:hover {
            color: var(--color-text-main);
            background: rgba(0, 0, 0, 0.015);
        }
        .segmented-btn.active {
            background: #ffffff;
            color: var(--color-cyan);
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .helper-text {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 6px 0;
            transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        /* Thumbs Styling */
        .slider-cyan::-webkit-slider-thumb { background: var(--color-cyan); box-shadow: 0 0 8px var(--color-cyan); }
        .slider-cyan::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-magenta::-webkit-slider-thumb { background: var(--color-magenta); box-shadow: 0 0 8px var(--color-magenta); }
        .slider-magenta::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-purple::-webkit-slider-thumb { background: var(--color-purple); box-shadow: 0 0 8px var(--color-purple); }
        .slider-purple::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .slider-cyan::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-cyan); }
        .slider-magenta::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-magenta); }
        .slider-purple::-moz-range-thumb { width: 18px; height: 18px; border: none; border-radius: 50%; background: var(--color-purple); }
        .select-wrapper {
            position: relative;
            display: flex;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
        }
        .custom-select {
            width: 100%;
            background: #f8fafc;
            border: none;
            outline: none;
            color: #0f172a;
            padding: 10px 14px;
            font-family: var(--font-body);
            font-size: 14px;
            font-weight: 600;
            appearance: none;
            cursor: pointer;
        }
        .select-arrow {
            position: absolute;
            right: 14px;
            top: 50%;
            transform: translateY(-50%);
            pointer-events: none;
            color: var(--color-text-muted);
            font-size: 12px;
        }
        .presets-section {
            display: flex;
            flex-direction: column;
            gap: 10px;
            border-top: 1px solid var(--color-border);
            padding-top: 16px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.04);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: var(--color-cyan);
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
        }
        .preset-name {
            font-size: 12px;
            font-weight: 600;
        }
        .simulation-panel {
            grid-column: 2;
            align-self: start;
        }
        .canvas-wrapper {
            position: relative;
            width: 100%;
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%);
            border: 1px solid rgba(0, 0, 0, 0.06);
            border-radius: 16px;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #physics-canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 16 / 11;
        }
        .canvas-overlay-data {
            position: absolute;
            top: 16px;
            left: 16px;
            pointer-events: none;
            display: flex;
            flex-direction: column;
            gap: 6px;
        }
        .overlay-item {
            background: rgba(255, 255, 255, 0.9);
            color: var(--color-text-main);
            backdrop-filter: blur(4px);
            border: 1px solid var(--color-border);
            padding: 6px 12px;
            border-radius: 8px;
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 11px;
        }
        .overlay-item .label {
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .overlay-item .value {
            font-weight: 700;
        }
        .simulation-metrics-strip {
            display: flex;
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 20px;
            justify-content: space-around;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
        }
        .mini-metric {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 4px;
            text-align: center;
        }
        .mini-metric .label {
            font-size: 10px;
            font-weight: 600;
            color: var(--color-text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        .mini-metric .value {
            font-size: 14px;
            font-weight: 700;
            color: var(--color-text-main);
            font-family: var(--font-heading);
        }
        .mini-divider {
            width: 1px;
            height: 24px;
            background: var(--color-border);
        }
        .results-panel {
            /* flex column inside right-column flow */
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, var(--color-cyan-glow) 0%, var(--color-purple-glow) 100%);
            border: 1px solid rgba(2, 132, 199, 0.15);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02);
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: var(--color-cyan);
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .ratio-type {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .results-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85);
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: var(--color-cyan);
            background: var(--color-cyan-glow);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
            transition: all 0.2s ease;
        }
        .result-card:hover .card-icon {
            color: var(--color-cyan);
            border-color: var(--color-cyan);
            background: var(--color-cyan-glow);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 17px;
            color: var(--color-text-main);
        }
        .formula-card {
            background: #ffffff;
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            font-size: 12px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        .formula-equation {
            font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace;
            color: #0284c7;
            font-size: 13px;
            background: #f8fafc;
            border-color: var(--color-border);
            padding: 8px 10px;
            border-radius: 6px;
        }
        /* Container Query for Responsiveness inside WP */
        @container bearinglife-container (max-width: 1024px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.bearinglife-calculator-wrapper .app-main-grid,
.bearinglife-calculator-wrapper .main-grid,
.bearinglife-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.bearinglife-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.bearinglife-calculator-wrapper .simulation-panel,
.bearinglife-calculator-wrapper .canvas-panel,
.bearinglife-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.bearinglife-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.bearinglife-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.bearinglife-calculator-wrapper .simulation-results-section .ratio-readout-box,
.bearinglife-calculator-wrapper .simulation-results-section .re-readout-box,
.bearinglife-calculator-wrapper .simulation-results-section .status-readout-box,
.bearinglife-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.bearinglife-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.bearinglife-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.bearinglife-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .bearinglife-calculator-wrapper .app-main-grid,
    .bearinglife-calculator-wrapper .main-grid,
    .bearinglife-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .bearinglife-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .bearinglife-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .bearinglife-calculator-wrapper .simulation-panel,
    .bearinglife-calculator-wrapper .canvas-panel,
    .bearinglife-calculator-wrapper .sim-panel,
    .bearinglife-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .bearinglife-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .bearinglife-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .bearinglife-calculator-wrapper .simulation-results-section .re-readout-box,
    .bearinglife-calculator-wrapper .simulation-results-section .status-readout-box,
    .bearinglife-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .bearinglife-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .bearinglife-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.bearinglife-calculator-wrapper .app-container,
.bearinglife-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.bearinglife-calculator-wrapper .simulation-results-section .formula-card,
.bearinglife-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 8px !important;
}
.bearinglife-calculator-wrapper .simulation-results-section .formula-card h4,
.bearinglife-calculator-wrapper .results-panel .formula-card h4 {
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
}
.bearinglife-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="bearinglife-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-compact-disc"></i></div>
                <div>
                    <h1>BEARING LIFE</h1>
                    <div class="subtitle">베어링 정격 수명 계산기 및 2D 회전 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">ISO 281 ENGINE ACTIVE</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>베어링 설계 변수</h2>
                </div>
                <!-- Bearing Type -->
                <div class="mode-select-container">
                    <span class="mode-label">베어링 전동체 형식</span>
                    <div class="segmented-control">
                        <button class="segmented-btn active" id="btn-type-ball" title="볼 베어링">볼 베어링 (p=3)</button>
                        <button class="segmented-btn" id="btn-type-roller" title="롤러 베어링">롤러 베어링 (p=3.33)</button>
                    </div>
                </div>
                <!-- Dynamic Load Rating C -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-c"><i class="fa-solid fa-shield-halved text-cyan"></i> 동 정격 하중 (C)</label>
                        <span class="helper-text">(10.0 ~ 500.0 kN)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-c" class="custom-number-input" min="10" max="500" value="45" step="any">
                        <div class="unit-badge">kN</div>
                    </div>
                    <input type="range" id="slider-c" class="custom-slider slider-cyan" min="10" max="500" value="45">
                </div>
                <!-- Radial Load Fr -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-fr"><i class="fa-solid fa-arrow-down text-magenta"></i> 반경방향 하중 (Fr)</label>
                        <span class="helper-text">(1.0 ~ 200.0 kN)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-fr" class="custom-number-input" min="1" max="200" value="12" step="any">
                        <div class="unit-badge">kN</div>
                    </div>
                    <input type="range" id="slider-fr" class="custom-slider slider-magenta" min="1" max="200" value="12">
                </div>
                <!-- Axial Load Fa -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-fa"><i class="fa-solid fa-arrow-right-long text-magenta"></i> 축방향 하중 (Fa)</label>
                        <span class="helper-text">(0.0 ~ 200.0 kN)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-fa" class="custom-number-input" min="0" max="200" value="3.5" step="any">
                        <div class="unit-badge">kN</div>
                    </div>
                    <input type="range" id="slider-fa" class="custom-slider slider-magenta" min="0" max="200" value="3.5">
                </div>
                <!-- Speed N -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-rpm"><i class="fa-solid fa-gauge-high text-purple"></i> 샤프트 회전수 (N)</label>
                        <span class="helper-text">(10 ~ 10000 RPM)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-rpm" class="custom-number-input" min="10" max="10000" value="1750" step="any">
                        <div class="unit-badge">RPM</div>
                    </div>
                    <input type="range" id="slider-rpm" class="custom-slider slider-purple" min="10" max="10000" value="1750">
                </div>
                <!-- Shock factor selection -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="select-fd"><i class="fa-solid fa-circle-exclamation text-purple"></i> 운전 하중 계수 (fd)</label>
                    </div>
                    <div class="select-wrapper">
                        <select id="select-fd" class="custom-select">
                            <option value="1.0">1.0 (정밀 가동, 무충격)</option>
                            <option value="1.2" selected>1.2 (일반 가동, 미세 충격)</option>
                            <option value="1.5">1.5 (고진동 장치, 강한 충격)</option>
                            <option value="2.0">2.0 (극심한 반복 충격 운전)</option>
                        </select>
                        <i class="fa-solid fa-chevron-down select-arrow"></i>
                    </div>
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 베어링 적용 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn active" id="preset-motor">
                            <div class="preset-icon"><i class="fa-solid fa-bolt"></i></div>
                            <div class="preset-details"><span class="preset-name">고속 산업 모터</span><span class="preset-spec">깊은홈볼, 경하중</span></div>
                        </button>
                        <button class="preset-btn" id="preset-turbine">
                            <div class="preset-icon"><i class="fa-solid fa-wind"></i></div>
                            <div class="preset-details"><span class="preset-name">풍력 메인 축</span><span class="preset-spec">롤러, 초고하중 저속</span></div>
                        </button>
                        <button class="preset-btn" id="preset-wheel">
                            <div class="preset-icon"><i class="fa-solid fa-car"></i></div>
                            <div class="preset-details"><span class="preset-name">자동차 휠 허브</span><span class="preset-spec">볼, 축-반경 혼합부하</span></div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <i class="fa-solid fa-dharmachakra text-magenta"></i>
                                    <h2>실시간 베어링 거동 및 접촉 응력 해석</h2>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas" width="640" height="400"></canvas>
                                    <div class="canvas-overlay-data">
                                        <div class="overlay-item">
                                            <span class="label">베어링 형식:</span>
                                            <span class="value" id="overlay-bearing-type">Ball Bearing</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <span class="label">반경/축 하중비 (Fa/Fr)</span>
                                        <span class="value" id="val-load-ratio">0.29</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label">동당량 하중 (P)</span>
                                        <span class="value" id="val-equiv-load">16.68 kN</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label">전동체 궤도 회전 속도</span>
                                        <span class="value" id="val-cage-speed">700 RPM</span>
                                    </div>
                                </div>
                                <!-- Integrated Results Analysis Section -->
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">계산된 정격 수명 (L10h)</div>
                                    <div class="ratio-value" id="txt-l10h">18,630 시간</div>
                                    <div class="ratio-type" id="txt-l10">1,956 백만회 회전</div>
                                </div>
                                <div class="results-grid">
                                        <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-weight-hanging text-success"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">설계 기본동적하중 (C)</span>
                                            <span class="card-value" id="res-c">45.00 kN</span>
                                        </div>
                                    </div>
                                        <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-arrows-spin text-purple"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">정적 동당량 하중 (P)</span>
                                            <span class="card-value" id="res-p">16.68 kN</span>
                                        </div>
                                    </div>
                                        <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-hourglass-half"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">수명 적합성 판정</span>
                                            <span class="card-value" id="res-status">적합 (일반 산업용)</span>
                                        </div>
                                    </div>
                                    </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-info-circle text-cyan"></i> 정격수명 공식 (ISO 281)</h4>
                                    <div class="formula-equation">
                                        L10 = (C / P)^p &nbsp;&nbsp;[p=3 or 3.33]
                                    </div>
                                    <div class="formula-equation">
                                        L10h = (10^6 × L10) / (60 × N)
                                    </div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- CORE INTERACTIVE ENGINE -->
    </div>
</div>
<script>
    // Polyfill for CanvasRenderingContext2D.roundRect for backward compatibility
    if (typeof CanvasRenderingContext2D !== 'undefined') {
        if (!CanvasRenderingContext2D.prototype.roundRect) {
        CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {
            if (typeof r === 'number') r = [r];
            if (!Array.isArray(r)) r = [0];
            const rad = r[0] || 0;
            this.beginPath();
            this.moveTo(x + rad, y);
            this.lineTo(x + w - rad, y);
            this.quadraticCurveTo(x + w, y, x + w, y + rad);
            this.lineTo(x + w, y + h - rad);
            this.quadraticCurveTo(x + w, y + h, x + w - rad, y + h);
            this.lineTo(x + rad, y + h);
            this.quadraticCurveTo(x, y + h, x, y + h - rad);
            this.lineTo(x, y + rad);
            this.quadraticCurveTo(x, y, x + rad, y);
            this.closePath();
            return this;
        };
      }
    }
        (function() {
            if (window.__bearinglife_initialized) return;
            window.__bearinglife_initialized = true;
            const btnTypeBall = document.getElementById('btn-type-ball');
            const btnTypeRoller = document.getElementById('btn-type-roller');
            const inputC = document.getElementById('input-c');
            const sliderC = document.getElementById('slider-c');
            const inputFr = document.getElementById('input-fr');
            const sliderFr = document.getElementById('slider-fr');
            const inputFa = document.getElementById('input-fa');
            const sliderFa = document.getElementById('slider-fa');
            const inputRpm = document.getElementById('input-rpm');
            const sliderRpm = document.getElementById('slider-rpm');
            const selectFd = document.getElementById('select-fd');
            const txtL10h = document.getElementById('txt-l10h');
            const txtL10 = document.getElementById('txt-l10');
            const valLoadRatio = document.getElementById('val-load-ratio');
            const valEquivLoad = document.getElementById('val-equiv-load');
            const valCageSpeed = document.getElementById('val-cage-speed');
            const resC = document.getElementById('res-c');
            const resP = document.getElementById('res-p');
            const resStatus = document.getElementById('res-status');
            const overlayBearingType = document.getElementById('overlay-bearing-type');
            const state = {
                type: 'ball', // 'ball' or 'roller'
                c: 45.0,
                fr: 12.0,
                fa: 3.5,
                rpm: 1750,
                fd: 1.2,
                angle: 0.0,
                lubricants: []
            };
            const ranges = {
                c: { min: 10.0, max: 500.0 },
                fr: { min: 1.0, max: 200.0 },
                fa: { min: 0.0, max: 200.0 },
                rpm: { min: 10.0, max: 10000.0 }
            };
            function calculateBearingLife() {
                let p_exponent = 3.0;
                if (state.type === 'roller') {
                    p_exponent = 3.333333;
                }
                let ratio = 0.0;
                if (state.fr > 0) {
                    ratio = state.fa / state.fr;
                } else {
                    ratio = 9999.0;
                }
                let X = 1.0;
                let Y = 0.0;
                if (state.type === 'ball') {
                    if (ratio > 0.25) {
                        X = 0.56;
                        Y = 1.4;
                    }
                } else {
                    if (ratio > 0.3) {
                        X = 0.4;
                        Y = 1.6;
                    }
                }
                const P_raw = X * state.fr + Y * state.fa;
                const P = state.fd * P_raw;
                let L10_rev = 0.0;
                if (P > 0) {
                    L10_rev = Math.pow(state.c / P, p_exponent);
                }
                const L10h_hours = (1000000.0 * L10_rev) / (60.0 * state.rpm);
                state.equivLoad = P;
                state.l10 = L10_rev;
                state.l10h = L10h_hours;
                state.loadRatio = ratio;
                updateUIValues();
            }
            function syncCFromInput() {
                let val = parseFloat(inputC.value);
                if (isNaN(val)) { val = ranges.c.min; }
                if (val < ranges.c.min) { val = ranges.c.min; }
                if (val > ranges.c.max) { val = ranges.c.max; }
                state.c = val;
                inputC.value = val.toFixed(1);
                sliderC.value = Math.round(val);
                calculateBearingLife();
            }
            function syncCFromSlider() {
                state.c = parseFloat(sliderC.value);
                inputC.value = state.c.toFixed(1);
                calculateBearingLife();
            }
            function syncFrFromInput() {
                let val = parseFloat(inputFr.value);
                if (isNaN(val)) { val = ranges.fr.min; }
                if (val < ranges.fr.min) { val = ranges.fr.min; }
                if (val > ranges.fr.max) { val = ranges.fr.max; }
                state.fr = val;
                inputFr.value = val.toFixed(1);
                sliderFr.value = Math.round(val);
                calculateBearingLife();
            }
            function syncFrFromSlider() {
                state.fr = parseFloat(sliderFr.value);
                inputFr.value = state.fr.toFixed(1);
                calculateBearingLife();
            }
            function syncFaFromInput() {
                let val = parseFloat(inputFa.value);
                if (isNaN(val)) { val = ranges.fa.min; }
                if (val < ranges.fa.min) { val = ranges.fa.min; }
                if (val > ranges.fa.max) { val = ranges.fa.max; }
                state.fa = val;
                inputFa.value = val.toFixed(1);
                sliderFa.value = Math.round(val);
                calculateBearingLife();
            }
            function syncFaFromSlider() {
                state.fa = parseFloat(sliderFa.value);
                inputFa.value = state.fa.toFixed(1);
                calculateBearingLife();
            }
            function syncRpmFromInput() {
                let val = parseFloat(inputRpm.value);
                if (isNaN(val)) { val = ranges.rpm.min; }
                if (val < ranges.rpm.min) { val = ranges.rpm.min; }
                if (val > ranges.rpm.max) { val = ranges.rpm.max; }
                state.rpm = val;
                inputRpm.value = val.toFixed(0);
                sliderRpm.value = Math.round(val);
                calculateBearingLife();
            }
            function syncRpmFromSlider() {
                state.rpm = parseFloat(sliderRpm.value);
                inputRpm.value = state.rpm.toFixed(0);
                calculateBearingLife();
            }
            function updateUIValues() {
                txtL10h.innerText = state.l10h.toLocaleString('ko-KR', { maximumFractionDigits: 0 }) + ' 시간';
                txtL10.innerText = state.l10.toLocaleString('ko-KR', { maximumFractionDigits: 1 }) + ' 백만회 회전';
                valLoadRatio.innerText = state.loadRatio.toFixed(2);
                valEquivLoad.innerText = state.equivLoad.toFixed(2) + ' kN';
                const cageRPM = state.rpm * 0.4;
                valCageSpeed.innerText = cageRPM.toFixed(0) + ' RPM';
                resC.innerText = state.c.toFixed(2) + ' kN';
                resP.innerText = state.equivLoad.toFixed(2) + ' kN';
                if (state.l10h < 2000.0) {
                    resStatus.innerText = '위험 (단기 피로 파손 우려)';
                    resStatus.style.color = '#db2777';
                } else {
                    if (state.l10h < 10000.0) {
                        resStatus.innerText = '보통 (경부하 간헐 가동)';
                        resStatus.style.color = '#f59e0b';
                    } else {
                        resStatus.innerText = '적합 (안정적 설계 수명)';
                        resStatus.style.color = '#10b981';
                    }
                }
                if (state.type === 'ball') {
                    overlayBearingType.innerText = '깊은 홈 볼 베어링 (Ball Bearing)';
                } else {
                    overlayBearingType.innerText = '원통형 롤러 베어링 (Roller Bearing)';
                }
            }
            function setBearingType(newType) {
                state.type = newType;
                if (newType === 'ball') {
                    btnTypeBall.classList.add('active');
                    btnTypeRoller.classList.remove('active');
                } else {
                    btnTypeRoller.classList.add('active');
                    btnTypeBall.classList.remove('active');
                }
                calculateBearingLife();
            }
            // Presets
            document.getElementById('preset-motor').addEventListener('click', function() {
                setActivePreset('preset-motor');
                state.c = 32.0;
                state.fr = 5.0;
                state.fa = 1.0;
                state.rpm = 3000;
                state.fd = 1.0;
                syncInputsToState();
                setBearingType('ball');
            });
            document.getElementById('preset-turbine').addEventListener('click', function() {
                setActivePreset('preset-turbine');
                state.c = 380.0;
                state.fr = 140.0;
                state.fa = 45.0;
                state.rpm = 25;
                state.fd = 1.5;
                syncInputsToState();
                setBearingType('roller');
            });
            document.getElementById('preset-wheel').addEventListener('click', function() {
                setActivePreset('preset-wheel');
                state.c = 68.0;
                state.fr = 18.0;
                state.fa = 15.0;
                state.rpm = 950;
                state.fd = 1.2;
                syncInputsToState();
                setBearingType('ball');
            });
            function setActivePreset(id) {
                document.getElementById('preset-motor').classList.remove('active');
                document.getElementById('preset-turbine').classList.remove('active');
                document.getElementById('preset-wheel').classList.remove('active');
                document.getElementById(id).classList.add('active');
            }
            function syncInputsToState() {
                inputC.value = state.c.toFixed(1);
                sliderC.value = Math.round(state.c);
                inputFr.value = state.fr.toFixed(1);
                sliderFr.value = Math.round(state.fr);
                inputFa.value = state.fa.toFixed(1);
                sliderFa.value = Math.round(state.fa);
                inputRpm.value = state.rpm;
                sliderRpm.value = state.rpm;
                selectFd.value = state.fd.toFixed(1);
            }
            // Canvas Drawing
            const canvas = document.getElementById('physics-canvas');
            const ctx = canvas.getContext('2d');
            function getDPR() {
                return window.devicePixelRatio || 1;
            }
            function initCanvas() {
                const dpr = getDPR();
                const rect = canvas.getBoundingClientRect();
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            window.addEventListener('resize', initCanvas);
            initCanvas();
            // Setup initial lubricants
            for (let i = 0; i < 40; i++) {
                state.lubricants.push({
                    r: Math.random() * 25 + 50,
                    angle: Math.random() * Math.PI * 2,
                    speed: Math.random() * 0.02 + 0.01,
                    size: Math.random() * 2 + 1
                });
            }
            let lastTime = 0;
            function animate(currentTime) {
                if (lastTime === 0) { lastTime = currentTime; }
                const dt = (currentTime - lastTime) / 1000;
                lastTime = currentTime;
                const dpr = getDPR();
                const width = canvas.width / dpr;
                const height = canvas.height / dpr;
                // Speed calculations
                const cageSpeed = (2.0 * Math.PI * state.rpm * 0.4) / 60.0;
                const shaftSpeed = (2.0 * Math.PI * state.rpm) / 60.0;
                state.angle += cageSpeed * dt;
                ctx.clearRect(0, 0, width, height);
                // 1. Grid
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.05)';
                ctx.lineWidth = 1;
                const gridSize = 25;
                for (let x = 0; x < width; x += gridSize) {
                    ctx.beginPath();
                    ctx.moveTo(x, 0);
                    ctx.lineTo(x, height);
                    ctx.stroke();
                }
                for (let y = 0; y < height; y += gridSize) {
                    ctx.beginPath();
                    ctx.moveTo(0, y);
                    ctx.lineTo(width, y);
                    ctx.stroke();
                }
                // Center position &#038; Dynamic Scale
                const cx = width / 2;
                const cy = height / 2;
                const baseSize = Math.min(width, height);
                const scale = (baseSize / 400) * 0.92;
                // 2. Outer Ring
                ctx.save();
                ctx.strokeStyle = '#475569';
                ctx.lineWidth = 14 * scale;
                ctx.beginPath();
                ctx.arc(cx, cy, 95 * scale, 0, Math.PI * 2);
                ctx.stroke();
                ctx.restore();
                // 3. Inner Ring
                ctx.save();
                ctx.strokeStyle = '#94a3b8';
                ctx.lineWidth = 14 * scale;
                ctx.beginPath();
                ctx.arc(cx, cy, 48 * scale, 0, Math.PI * 2);
                ctx.stroke();
                // Draw shaft rotation indicators
                ctx.translate(cx, cy);
                ctx.rotate(state.angle * 2.5); // rotates faster than cage
                ctx.fillStyle = '#1e293b';
                ctx.beginPath();
                ctx.arc(0, 0, 41 * scale, 0, Math.PI * 2);
                ctx.fill();
                ctx.strokeStyle = 'rgba(255,255,255,0.15)';
                ctx.lineWidth = 4 * scale;
                ctx.beginPath();
                ctx.moveTo(-35 * scale, 0);
                ctx.lineTo(35 * scale, 0);
                ctx.moveTo(0, -35 * scale);
                ctx.lineTo(0, 35 * scale);
                ctx.stroke();
                ctx.restore();
                // 4. Draw Lubricants
                ctx.fillStyle = 'rgba(2, 132, 199, 0.35)';
                for (let i = 0; i < state.lubricants.length; i++) {
                    const l = state.lubricants[i];
                    l.angle += l.speed * Math.max(state.rpm / 200, 1.0) * dt * 10;
                    const lx = cx + Math.cos(l.angle) * l.r * scale;
                    const ly = cy + Math.sin(l.angle) * l.r * scale;
                    ctx.beginPath();
                    ctx.arc(lx, ly, l.size * scale, 0, Math.PI * 2);
                    ctx.fill();
                }
                // 5. Draw Stress Glow zone (Radial load pushes down on bottom)
                if (state.fr > 0) {
                    ctx.save();
                    const stressIntensity = Math.min(state.fr / 100.0, 1.0);
                    const grad = ctx.createRadialGradient(cx, cy + 30 * scale, 20 * scale, cx, cy + 85 * scale, 95 * scale);
                    grad.addColorStop(0, 'rgba(219, 39, 119, 0.0)');
                    grad.addColorStop(1, 'rgba(219, 39, 119, ' + (0.45 * stressIntensity) + ')');
                    ctx.fillStyle = grad;
                    ctx.beginPath();
                    ctx.arc(cx, cy, 95 * scale, 0, Math.PI);
                    ctx.lineTo(cx, cy);
                    ctx.closePath();
                    ctx.fill();
                    ctx.restore();
                }
                // 6. Draw Rolling Elements (Balls or Rollers)
                const count = state.type === 'ball' ? 9 : 12;
                ctx.save();
                for (let i = 0; i < count; i++) {
                    const a = state.angle + (i * Math.PI * 2) / count;
                    const rx = cx + Math.cos(a) * 71.5 * scale;
                    const ry = cy + Math.sin(a) * 71.5 * scale;
                    // Compute individual stress load
                    const angleOffset = Math.abs((a % (Math.PI * 2)) - Math.PI / 2);
                    let elementStress = 0.0;
                    if (angleOffset < Math.PI / 2) {
                        elementStress = Math.cos(angleOffset) * (state.fr / 150.0);
                    }
                    elementStress += state.fa / 200.0;
                    if (elementStress > 1.0) { elementStress = 1.0; }
                    if (state.type === 'ball') {
                        // Ball drawing
                        ctx.save();
                        ctx.beginPath();
                        ctx.arc(rx, ry, 11.5 * scale, 0, Math.PI * 2);
                        ctx.fillStyle = '#cbd5e1';
                        ctx.fill();
                        ctx.lineWidth = 1.5 * scale;
                        ctx.strokeStyle = '#475569';
                        ctx.stroke();
                        if (elementStress > 0.05) {
                            ctx.beginPath();
                            ctx.arc(rx, ry, 11.5 * scale, 0, Math.PI * 2);
                            ctx.fillStyle = 'rgba(219, 39, 119, ' + (elementStress * 0.6) + ')';
                            ctx.fill();
                        }
                        ctx.restore();
                    } else {
                        // Roller drawing (rectangles)
                        ctx.save();
                        ctx.translate(rx, ry);
                        ctx.rotate(a);
                        ctx.fillStyle = '#cbd5e1';
                        ctx.beginPath();
                        ctx.roundRect(-10 * scale, -11.5 * scale, 20 * scale, 23 * scale, 3 * scale);
                        ctx.fill();
                        ctx.lineWidth = 1.5 * scale;
                        ctx.strokeStyle = '#475569';
                        ctx.stroke();
                        if (elementStress > 0.05) {
                            ctx.beginPath();
                            ctx.roundRect(-10 * scale, -11.5 * scale, 20 * scale, 23 * scale, 3 * scale);
                            ctx.fillStyle = 'rgba(219, 39, 119, ' + (elementStress * 0.6) + ')';
                            ctx.fill();
                        }
                        ctx.restore();
                    }
                }
                ctx.restore();
                // 7. Load Vector Arrows
                if (state.fr > 0) {
                    ctx.save();
                    ctx.strokeStyle = '#db2777';
                    ctx.fillStyle = '#db2777';
                    ctx.lineWidth = Math.min(state.fr * 0.04 + 2, 7) * scale;
                    ctx.shadowBlur = 8 * scale;
                    ctx.shadowColor = '#db2777';
                    // Vertical arrow
                    const arrowTop = Math.max(cy - 120 * scale, 22 * scale);
                    ctx.beginPath();
                    ctx.moveTo(cx, arrowTop);
                    ctx.lineTo(cx, cy - 55 * scale);
                    ctx.stroke();
                    // Arrowhead
                    ctx.beginPath();
                    ctx.moveTo(cx, cy - 52 * scale);
                    ctx.lineTo(cx - 8 * scale, cy - 65 * scale);
                    ctx.lineTo(cx + 8 * scale, cy - 65 * scale);
                    ctx.closePath();
                    ctx.fill();
                    // Text
                    ctx.fillStyle = '#db2777';
                    ctx.font = 'bold ' + Math.max(9, Math.round(11 * scale)) + 'px Inter';
                    ctx.fillText('Radial Load Fr = ' + state.fr.toFixed(1) + ' kN', cx + 12 * scale, arrowTop + 14 * scale);
                    ctx.restore();
                }
                // Axial Arrow (Fa) pushing side-on to shaft center
                if (state.fa > 0) {
                    ctx.save();
                    ctx.strokeStyle = '#0284c7';
                    ctx.fillStyle = '#0284c7';
                    ctx.lineWidth = Math.min(state.fa * 0.04 + 2, 7) * scale;
                    ctx.shadowBlur = 8 * scale;
                    ctx.shadowColor = '#0284c7';
                    // Horizontal arrow
                    ctx.beginPath();
                    ctx.moveTo(cx - 215 * scale, cy);
                    ctx.lineTo(cx - 115 * scale, cy);
                    ctx.stroke();
                    // Arrowhead
                    ctx.beginPath();
                    ctx.moveTo(cx - 112 * scale, cy);
                    ctx.lineTo(cx - 125 * scale, cy - 8 * scale);
                    ctx.lineTo(cx - 125 * scale, cy + 8 * scale);
                    ctx.closePath();
                    ctx.fill();
                    // Text
                    ctx.fillStyle = '#0284c7';
                    ctx.font = 'bold ' + Math.max(9, Math.round(11 * scale)) + 'px Inter';
                    ctx.fillText('Axial Fa = ' + state.fa.toFixed(1) + ' kN', cx - 205 * scale, cy - 12 * scale);
                    ctx.restore();
                }
                requestAnimationFrame(animate);
            }
            requestAnimationFrame(animate);
            // Bind Event Listeners
            btnTypeBall.addEventListener('click', function() { setBearingType('ball'); });
            btnTypeRoller.addEventListener('click', function() { setBearingType('roller'); });
            inputC.addEventListener('change', syncCFromInput);
            sliderC.addEventListener('input', syncCFromSlider);
            inputFr.addEventListener('change', syncFrFromInput);
            sliderFr.addEventListener('input', syncFrFromSlider);
            inputFa.addEventListener('change', syncFaFromInput);
            sliderFa.addEventListener('input', syncFaFromSlider);
            inputRpm.addEventListener('change', syncRpmFromInput);
            sliderRpm.addEventListener('input', syncRpmFromSlider);
            selectFd.addEventListener('change', function() {
                state.fd = parseFloat(selectFd.value);
                calculateBearingLife();
            });
            // Initial Calculations
            calculateBearingLife();
            // Right click / Copy Protection
            (function() {
                function blockEvents() {
                    document.addEventListener('contextmenu', function(e) {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }, { capture: true });
                    document.addEventListener('selectstart', function(e) {
                        e.preventDefault();
                        return false;
                    }, { capture: true });
                    document.addEventListener('keydown', function(e) {
                        if (e.key === 'F12') {
                            e.preventDefault();
                            alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                            return false;
                        }
                        if (e.ctrlKey) {
                            if (e.key === 'u' || e.key === 'c' || e.key === 's') {
                                e.preventDefault();
                                alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                                return false;
                            }
                        }
                    }, { capture: true });
                }
                if (document.readyState === 'complete' || document.readyState === 'interactive') {
                    blockEvents();
                } else {
                    document.addEventListener('DOMContentLoaded', blockEvents);
                }
            })();
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>베어링 형식 선택: 깊은 홈 볼 베어링(지수 p=3) 또는 롤러 베어링(지수 p=3.33)을 설정합니다.</strong></li>
<li style="margin-bottom: 6px;">설계 제어 변수 조절: 기본 동적 부하 용량(C), 반경방향 하중(Fr), 축방향 하중(Fa), 회전 속도(RPM) 슬라이더를 조절합니다.</li>
<li style="margin-bottom: 6px;">충격 계수 선택: 기계의 진동 및 충격 조건에 따라 하중 계수(fd)를 지정합니다.</li>
<li style="margin-bottom: 6px;">실시간 응력 가시화 확인: 2D 베어링 시뮬레이터 내부에서 전동체(Ball/Roller)와 와이어프레임 궤도 접촉 부위에 작용하는 응력 집중도(Magenta/Red Glow)를 확인합니다.</li>
<li style="margin-bottom: 6px;">수명 판정 및 출력값 분석: 계산서에서 회전수 기준 수명(L10)과 시간 기준 정격수명(L10h)이 장비 권장 수명 범위를 충족하는지 실시간 판정합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 기계공학 해설 및 설계 규격 (ISO 281) 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 베어링의 피로 수명 및 L10 수명의 물리학적 정의</h3>
<p>회전 기계 요소 설계에서 <strong>구름 베어링(Rolling Bearing)</strong>의 수명은 궤도륜(Ring) 또는 전동체(Rolling Element)의 재료에 최초로 반복 피로에 의한 박리(Flaking / Spalling) 현상이 나타날 때까지의 총 회전수 또는 운전 시간으로 정의됩니다. 동일한 규격의 베어링들을 동일한 조건에서 운전하더라도 재료 피로의 통계적 특성으로 인해 개별 수명은 넓은 분포를 보입니다.</p><p>이에 따라 ISO 281 규격은 <strong>정격 수명 L<sub>10</sub> (Nominal Fatigue Life)</strong>을 표준으로 삼고 있습니다. 이는 <em>동일한 군의 베어링들 중 90%가 피로 손상 없이 도달할 수 있는 신뢰도 90%의 통계적 수명</em>을 의미합니다. 만약 신뢰도를 95%나 99%로 올리고자 한다면, 신뢰도 보정 계수(a<sub>1</sub>)를 곱하는 수정 정격 수명(L<sub>10m</sub>) 공식을 사용해야 합니다.</p>
<h3>2. ISO 281 정격 수명 기본 계산식 및 인자 분석</h3>
<p>베어링의 기본 피로 수명 공식은 다음과 같습니다:</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">L<sub>10</sub> = (C / P)<sup>p</sup> &nbsp;[10<sup>6</sup> 회전]</p><p>여기서 인자들은 다음과 같이 정의됩니다:</p><ul><li><strong>C: 기본 동정격 하중 (Basic Dynamic Load Rating, kN)</strong> &#8211; 100만 회전의 정격 수명을 가질 때 베어링이 견딜 수 있는 일정한 크기와 방향의 순수 하중을 뜻하며 베어링 규격표(Catalog)에 명시됩니다.</li><li><strong>P: 동당량 하중 (Equivalent Dynamic Load, kN)</strong> &#8211; 실제 베어링에 가해지는 반경방향 하중(F<sub>r</sub>)과 축방향 하중(F<sub>a</sub>)의 합성치이며, 운전 중 충격 진동을 고려하기 위해 충격 계수(f<sub>d</sub>)를 반영하여 다음과 같이 산정합니다: <code>P = f<sub>d</sub> &times; (X &middot; F<sub>r</sub> + Y &middot; F<sub>a</sub>)</code>.</li><li><strong>p: 수명 지수 (Life Exponent)</strong> &#8211; 접촉 형상에 따라 다르며 <strong>볼 베어링은 p = 3</strong>, <strong>롤러 베어링은 p = 10/3 (3.333)</strong>을 적용합니다.</li></ul><p>시간 기준 수명(L<sub>10h</sub>)은 회전 속도 <code>N [RPM]</code>을 적용하여 시간 단위(Hours)로 변환해 유도합니다:</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.1em; color: #0369a1;">L<sub>10h</sub> = (10<sup>6</sup> &times; L<sub>10</sub>) / (60 &times; N) &nbsp;[시간, Hours]</p>
<h3>3. 산업 분야별 권장 베어링 목표 수명 가이드</h3>
<p>기계설계 시 사용 수명이 설계 목표를 만족하는지 검토해야 하며, 일반적으로 널리 쓰이는 가이드라인은 다음과 같습니다:</p><ul><li><strong>단시간 또는 단속 운전 기계 (가전제품, 수동 전동공구 등):</strong> 500 ~ 2,000 시간</li><li><strong>단시간 가동되나 신뢰성이 중요한 장비 (비상용 펌프, 단기 운전 크레인):</strong> 2,000 ~ 8,000 시간</li><li><strong>일반 산업 기계 및 주간 가동 공장 설비 (컨베이어, 일반 송풍기):</strong> 10,000 ~ 20,000 시간</li><li><strong>24시간 연속 운전 기계 및 고신뢰성 필수 설비 (발전소 펌프, 대형 압축기, 선박 추진계):</strong> 40,000 ~ 100,000 시간 이상</li></ul>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/bearing-life-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>선끝속도 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/linear-tip-speed-simulator-calculator/</link>
					<comments>https://myengnote.com/linear-tip-speed-simulator-calculator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Wed, 27 May 2026 05:12:57 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[물리시뮬레이터]]></category>
		<category><![CDATA[선끝속도]]></category>
		<category><![CDATA[원심력 가속도]]></category>
		<category><![CDATA[접선속도]]></category>
		<category><![CDATA[회전속도 계산]]></category>
		<guid isPermaLink="false">https://myengnote.com/linear-tip-speed-simulator-calculator/</guid>

					<description><![CDATA[지름과 회전수(RPM)를 입력하여 선끝속도(접선 속도)를 실시간으로 계산하고 시각화하는 초정밀 2D 물리 시뮬레이터입니다.]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 선끝속도 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for rotaspeed-calculator-wrapper */
        .rotaspeed-calculator-wrapper *, .rotaspeed-calculator-wrapper *::before, .rotaspeed-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .rotaspeed-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7;
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777;
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .rotaspeed-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.15;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-magenta);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.12; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.22; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-dark));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .fa-spin-slow {
            animation: fa-spin 12s linear infinite;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: #0284c7; }
        .text-magenta { color: #db2777; }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .helper-text {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .unit-selector-wrapper {
            position: relative;
        }
        .custom-select {
            background: rgba(0, 0, 0, 0.02);
            border: 1px solid var(--color-border);
            color: var(--color-text-main);
            padding: 4px 10px;
            border-radius: 6px;
            font-size: 11px;
            font-weight: 600;
            cursor: pointer;
            outline: none;
            transition: all 0.2s ease;
        }
        .custom-select:hover, .custom-select:focus {
            background: rgba(0, 0, 0, 0.03);
            border-color: var(--color-border);
        }
        .input-control-row {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 8px 0;
            transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        .custom-slider::-moz-range-thumb {
            width: 18px;
            height: 18px;
            border: none;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-diameter::-webkit-slider-thumb {
            background: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan);
        }
        #slider-diameter::-moz-range-thumb {
            background: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan);
        }
        #slider-diameter::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-cyan), 0 0 5px #fff;
        }
        #slider-diameter::-moz-range-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-cyan), 0 0 5px #fff;
        }
        #slider-rpm::-webkit-slider-thumb {
            background: var(--color-magenta);
            box-shadow: 0 0 10px var(--color-magenta);
        }
        #slider-rpm::-moz-range-thumb {
            background: var(--color-magenta);
            box-shadow: 0 0 10px var(--color-magenta);
        }
        #slider-rpm::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-magenta), 0 0 5px #fff;
        }
        #slider-rpm::-moz-range-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-magenta), 0 0 5px #fff;
        }
        .control-actions {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-top: 10px;
        }
        #btn-particles {
            grid-column: span 2;
        }
        .action-btn {
            background: rgba(0, 0, 0, 0.02);
            border: 1px solid var(--color-border);
            color: var(--color-text-main);
            padding: 10px;
            border-radius: 10px;
            font-size: 12px;
            font-weight: 600;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
        }
        .action-btn:hover {
            background: rgba(0, 0, 0, 0.03);
            border-color: var(--color-border);
        }
        .action-btn.active#btn-particles {
            background: var(--color-magenta-glow);
            border-color: #db2777;
            color: #db2777;
            box-shadow: 0 0 12px var(--color-magenta-glow);
        }
        .presets-section {
            display: flex;
            flex-direction: column;
            gap: 12px;
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: grid;
            grid-template-columns: 1fr;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            border-color: var(--color-border);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-purple-glow));
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: #0284c7;
            transition: all 0.2s ease;
        }
        .preset-btn:hover .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
            box-shadow: var(--shadow-neon-cyan);
        }
        .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
        }
        .preset-name {
            font-size: 12px;
            font-weight: 600;
            letter-spacing: 0.25px;
        }
        .simulation-panel {
            grid-column: 2;
            align-self: start;
        }
        .simulation-panel .panel-header {
            justify-content: space-between;
        }
        .canvas-scale-indicator {
            font-size: 11px;
            color: var(--color-text-muted);
            background: rgba(0, 0, 0, 0.02);
            padding: 4px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
        }
        .canvas-wrapper {
            position: relative;
            width: 100%;
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%);
            border: 1px solid rgba(0, 0, 0, 0.06);
            border-radius: 16px;
            overflow: hidden;
        }
        #physics-canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 1 / 1;
        }
        .canvas-overlay-data {
            position: absolute;
            top: 16px;
            left: 16px;
            pointer-events: none;
        }
        .overlay-item {
            background: rgba(255, 255, 255, 0.85);
            backdrop-filter: blur(4px);
            border: 1px solid var(--color-border);
            padding: 6px 12px;
            border-radius: 8px;
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 11px;
        }
        .overlay-item .label {
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .overlay-item .value {
            font-family: var(--font-body);
            font-weight: 700;
        }
        .simulation-metrics-strip {
            display: flex;
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 20px;
            justify-content: space-around;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
        }
        .mini-metric {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 4px;
            text-align: center;
        }
        .mini-metric .label {
            font-size: 10px;
            font-weight: 600;
            color: var(--color-text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        .mini-metric .value {
            font-size: 14px;
            font-weight: 700;
            color: var(--color-text-main);
            font-family: var(--font-heading);
        }
        .mini-divider {
            width: 1px;
            height: 24px;
            background: rgba(0, 0, 0, 0.03);
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(219, 39, 119, 0.08) 0%, rgba(124, 58, 237, 0.03) 100%);
            border: 1px solid rgba(219, 39, 119, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            box-shadow: 0 0 15px rgba(219, 39, 119, 0.05);
            margin: 10px 0;
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: #db2777;
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 26px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .ratio-type {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85);
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(219, 39, 119, 0.2);
            background: rgba(219, 39, 119, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
            transition: all 0.2s ease;
        }
        .result-card:hover .card-icon {
            color: #db2777;
            border-color: rgba(219, 39, 119, 0.3);
            background: rgba(219, 39, 119, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 17px;
            color: var(--color-text-main);
        }
        .formula-card {
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            font-size: 12px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        .formula-equation {
            font-family: monospace;
            color: #db2777;
            font-size: 13px;
            background: #f8fafc;
            border-color: var(--color-border);
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        /* Container Query for Responsiveness inside WP */
        @container rotaspeed-container (max-width: 1024px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.rotaspeed-calculator-wrapper .app-main-grid,
.rotaspeed-calculator-wrapper .main-grid,
.rotaspeed-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.rotaspeed-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.rotaspeed-calculator-wrapper .simulation-panel,
.rotaspeed-calculator-wrapper .canvas-panel,
.rotaspeed-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.rotaspeed-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.rotaspeed-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.rotaspeed-calculator-wrapper .simulation-results-section .ratio-readout-box,
.rotaspeed-calculator-wrapper .simulation-results-section .re-readout-box,
.rotaspeed-calculator-wrapper .simulation-results-section .status-readout-box,
.rotaspeed-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.rotaspeed-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.rotaspeed-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.rotaspeed-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .rotaspeed-calculator-wrapper .app-main-grid,
    .rotaspeed-calculator-wrapper .main-grid,
    .rotaspeed-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .rotaspeed-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .rotaspeed-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .rotaspeed-calculator-wrapper .simulation-panel,
    .rotaspeed-calculator-wrapper .canvas-panel,
    .rotaspeed-calculator-wrapper .sim-panel,
    .rotaspeed-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .rotaspeed-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .rotaspeed-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .rotaspeed-calculator-wrapper .simulation-results-section .re-readout-box,
    .rotaspeed-calculator-wrapper .simulation-results-section .status-readout-box,
    .rotaspeed-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .rotaspeed-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .rotaspeed-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.rotaspeed-calculator-wrapper .app-container,
.rotaspeed-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.rotaspeed-calculator-wrapper .simulation-results-section .formula-card,
.rotaspeed-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 8px !important;
}
.rotaspeed-calculator-wrapper .simulation-results-section .formula-card h4,
.rotaspeed-calculator-wrapper .results-panel .formula-card h4 {
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
}
.rotaspeed-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="rotaspeed-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- HEADER -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-circle-notch fa-spin-slow"></i></div>
                <div>
                    <h1>ROTASPEED</h1>
                    <p class="subtitle">Linear Tip Speed Simulator &#038; Calculator</p>
                </div>
            </div>
            <div class="header-badge">
                <span class="pulse-dot"></span>
                <span class="badge-text">실시간 물리 엔진 구동 중</span>
            </div>
        </header>
        <!-- MAIN GRID LAYOUT -->
        <main class="app-main-grid">
            <!-- LEFT PANEL: CONTROLS & PRESETS -->
            <section class="panel control-panel" aria-label="입력 제어판">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>시뮬레이터 제어</h2>
                </div>
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-diameter"><i class="fa-solid fa-arrows-left-right"></i> 회전체 지름 (Diameter)</label>
                        <div class="unit-selector-wrapper">
                            <select id="select-diameter-unit" class="custom-select" aria-label="지름 단위 선택">
                                <option value="mm" selected>mm</option>
                                <option value="cm">cm</option>
                                <option value="m">m</option>
                                <option value="inch">inch</option>
                            </select>
                        </div>
                    </div>
                    <div class="input-control-row">
                        <input type="range" id="slider-diameter" min="1" max="2000" step="1" value="500" class="custom-slider" aria-label="지름 슬라이더">
                        <div class="number-input-wrapper">
                            <input type="number" id="input-diameter" value="500" min="0.001" step="any" class="custom-number-input" style="background: #f8fafc !important; color: #0f172a !important;">
                            <span class="unit-badge" id="diameter-unit-label">mm</span>
                        </div>
                    </div>
                </div>
                <div class="input-group">
                    <div class="input-label-row">
                        <label for="input-rpm"><i class="fa-solid fa-gauge-high"></i> 회전수 (Rotational Speed)</label>
                        <span class="helper-text">RPM (Revolutions Per Minute)</span>
                    </div>
                    <div class="input-control-row">
                        <input type="range" id="slider-rpm" min="0" max="8000" step="1" value="1500" class="custom-slider" aria-label="회전수 슬라이더">
                        <div class="number-input-wrapper">
                            <input type="number" id="input-rpm" value="1500" min="0" step="any" class="custom-number-input" style="background: #f8fafc !important; color: #0f172a !important;">
                            <span class="unit-badge">RPM</span>
                        </div>
                    </div>
                </div>
                <div class="control-actions">
                    <button id="btn-play-pause" class="action-btn" title="일시정지/재생" aria-label="일시정지 및 재생">
                        <i class="fa-solid fa-pause"></i> <span>일시정지</span>
                    </button>
                    <button id="btn-reverse" class="action-btn" title="회전 방향 전환" aria-label="회전 방향 전환">
                        <i class="fa-solid fa-rotate-left"></i> <span>방향 전환</span>
                    </button>
                    <button id="btn-particles" class="action-btn active" title="스파크 시각 효과 토글" aria-label="스파크 효과 토글">
                        <i class="fa-solid fa-wand-magic-sparkles"></i> <span>스파크 이펙트</span>
                    </button>
                </div>
                <div class="presets-section">
                    <h3><i class="fa-solid fa-list-check text-magenta"></i> 사전 정의 프리셋 (Presets)</h3>
                    <div class="presets-grid">
                        <button class="preset-btn" data-preset="bicycle" aria-label="자전거 바퀴 프리셋">
                            <span class="preset-icon"><i class="fa-solid fa-bicycle"></i></span>
                            <div class="preset-details">
                                <span class="preset-name">자전거 바퀴</span>
                                <span class="preset-spec">27.5인치, 270 RPM</span>
                            </div>
                        </button>
                        <button class="preset-btn" data-preset="grinder" aria-label="고속 그라인더 프리셋">
                            <span class="preset-icon"><i class="fa-solid fa-compact-disc"></i></span>
                            <div class="preset-details">
                                <span class="preset-name">앵글 그라인더</span>
                                <span class="preset-spec">125mm, 11000 RPM</span>
                            </div>
                        </button>
                        <button class="preset-btn" data-preset="turbine" aria-label="풍력 발전기 프리셋">
                            <span class="preset-icon"><i class="fa-solid fa-wind"></i></span>
                            <div class="preset-details">
                                <span class="preset-name">풍력 터빈</span>
                                <span class="preset-spec">120m, 15 RPM</span>
                            </div>
                        </button>
                        <button class="preset-btn" data-preset="hdd" aria-label="HDD 디스크 프리셋">
                            <span class="preset-icon"><i class="fa-solid fa-hdd"></i></span>
                            <div class="preset-details">
                                <span class="preset-name">HDD 플래터</span>
                                <span class="preset-spec">3.5인치, 7200 RPM</span>
                            </div>
                        </button>
                        <button class="preset-btn" data-preset="earth" aria-label="지구 자전 프리셋">
                            <span class="preset-icon"><i class="fa-solid fa-earth-asia"></i></span>
                            <div class="preset-details">
                                <span class="preset-name">지구 자전</span>
                                <span class="preset-spec">적도 (12,742km)</span>
                            </div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel" aria-label="물리 애니메이션 시뮬레이션">
                                <div class="panel-header">
                                    <i class="fa-solid fa-dharmachakra text-magenta"></i>
                                    <h2>실시간 회전 시뮬레이션</h2>
                                    <span class="canvas-scale-indicator" id="canvas-scale-text">화면 스케일: 자동</span>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas" width="600" height="480"></canvas>
                                    <div class="canvas-overlay-data">
                                        <div class="overlay-item">
                                            <span class="label">선속도 벡터 길이:</span>
                                            <span class="value text-cyan" id="overlay-vector-val">0.00 m/s</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <span class="label">주파수 (Frequency)</span>
                                        <span class="value" id="val-frequency">25.0 Hz</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label">각속도 (Angular Velocity)</span>
                                        <span class="value" id="val-angular-speed">157.1 rad/s</span>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <span class="label">향심가속도 (Centripetal Accel.)</span>
                                        <span class="value" id="val-centripetal-g">64.2 G</span>
                                    </div>
                                </div>
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title">접선 선끝속도 (Tangential Tip Speed)</div>
                                    <div id="gauge-primary-value" class="ratio-value">39.27</div>
                                    <div class="ratio-type">m/s (초속)</div>
                                </div>
                                <div class="results-grid">
                                    <div class="result-card" id="card-ms">
                                        <div class="card-icon"><i class="fa-solid fa-gauge-simple-high text-magenta"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">접선 속도 (v)</span>
                                            <span class="card-value" id="val-ms">0.00 m/s</span>
                                        </div>
                                    </div>
                                    <div class="result-card" id="card-kmh">
                                        <div class="card-icon"><i class="fa-solid fa-gauge"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">접선 시속 (v)</span>
                                            <span class="card-value" id="val-kmh">0.0 km/h</span>
                                        </div>
                                    </div>
                                    <div class="result-card" id="card-mmin">
                                        <div class="card-icon"><i class="fa-solid fa-stopwatch"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">분당 속도 (v)</span>
                                            <span class="card-value" id="val-mmin">0 m/min</span>
                                        </div>
                                    </div>
                                    <div class="result-card" id="card-mph">
                                        <div class="card-icon"><i class="fa-solid fa-wind text-cyan"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit">시속 (mph)</span>
                                            <span class="card-value" id="val-mph">87.8</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4><i class="fa-solid fa-circle-info text-cyan"></i> 선끝속도 물리 공식</h4>
                                    <div class="formula-equation">
                                        v = π × D × (N / 60)
                                    </div>
                                    <div class="formula-desc">
                                        <div>• <strong>v</strong> : 선끝속도 (m/s)</div>
                                        <div>• <strong>D</strong> : 지름 (m)</div>
                                        <div>• <strong>N</strong> : 회전수 (RPM)</div>
                                    </div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- MathJax for rendering gorgeous equations -->
    <!-- CORE SIMULATION LOGIC -->
    </div>
</div>
<script>
window.MathJax = {
tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']],
displayMath: [['$$', '$$'], ['\\[', '\\]']]
},
svg: {
fontCache: 'global'
}
};
</script>
<script type="text/javascript" id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
<script>
(function() {
if (window.__rotaspeed_initialized) return;
function initRotaspeed() {
if (window.__rotaspeed_initialized) return;
const selectUnit = document.getElementById('select-diameter-unit');
const sliderDiameter = document.getElementById('slider-diameter');
const inputDiameter = document.getElementById('input-diameter');
const canvas = document.getElementById('physics-canvas');
if (!selectUnit || !sliderDiameter || !inputDiameter || !canvas) {
return;
}
window.__rotaspeed_initialized = true;
const labelDiameterUnit = document.getElementById('diameter-unit-label');
const sliderRpm = document.getElementById('slider-rpm');
const inputRpm = document.getElementById('input-rpm');
const btnPlayPause = document.getElementById('btn-play-pause');
const btnReverse = document.getElementById('btn-reverse');
const btnParticles = document.getElementById('btn-particles');
const presetButtons = document.querySelectorAll('.preset-btn');
const txtFrequency = document.getElementById('val-frequency');
const txtAngularSpeed = document.getElementById('val-angular-speed');
const txtCentripetalG = document.getElementById('val-centripetal-g');
const txtCanvasScale = document.getElementById('canvas-scale-text');
const gaugeProgress = document.getElementById('gauge-progress');
const txtGaugePrimaryValue = document.getElementById('gauge-primary-value');
const txtMs = document.getElementById('val-ms');
const txtKmh = document.getElementById('val-kmh');
const txtMmin = document.getElementById('val-mmin');
const txtMph = document.getElementById('val-mph');
const txtOverlayVectorVal = document.getElementById('overlay-vector-val');
const ctx = canvas.getContext('2d');
function resizeCanvas() {
const dpr = window.devicePixelRatio || 1;
const wrapper = canvas.parentElement;
if (!wrapper) return;
let targetWidth = wrapper.clientWidth;
let targetHeight = targetWidth;
if (targetWidth < 50) {
targetWidth = 500;
targetHeight = 500;
}
canvas.width = targetWidth * dpr;
canvas.height = targetHeight * dpr;
ctx.scale(dpr, dpr);
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
window.addEventListener('load', resizeCanvas);
setTimeout(resizeCanvas, 100);
setTimeout(resizeCanvas, 400);
setTimeout(resizeCanvas, 1000);
let state = {
diameterMeters: 0.5,
rpm: 1500,
isPlaying: true,
direction: 1,
showParticles: true,
currentUnit: 'mm',
angle: 0,
lastTime: performance.now(),
particles: []
};
const unitConfigs = {
mm: {
label: 'mm',
toMeters: (val) => val / 1000,
fromMeters: (m) => m * 1000,
slider: { min: 1, max: 2000, step: 1 }
},
cm: {
label: 'cm',
toMeters: (val) => val / 100,
fromMeters: (m) => m * 100,
slider: { min: 0.1, max: 200, step: 0.1 }
},
m: {
label: 'm',
toMeters: (val) => val,
fromMeters: (m) => m,
slider: { min: 0.001, max: 25, step: 0.001 }
},
inch: {
label: 'inch',
toMeters: (val) => val * 0.0254,
fromMeters: (m) => m / 0.0254,
slider: { min: 0.1, max: 80, step: 0.1 }
}
};
const presets = {
bicycle: {
name: '자전거 바퀴 (27.5인치)',
diameter: 0.7,
rpm: 270,
unit: 'mm'
},
grinder: {
name: '초고속 앵글 그라인더',
diameter: 0.125,
rpm: 11000,
unit: 'mm'
},
turbine: {
name: '초대형 풍력 터빈',
diameter: 120,
rpm: 15,
unit: 'm'
},
hdd: {
name: '컴퓨터 하드디스크 Platter',
diameter: 0.0889,
rpm: 7200,
unit: 'inch'
},
earth: {
name: '지구 자전 (적도 둘레)',
diameter: 12742000,
rpm: 0.0006944,
unit: 'm'
}
};
function calculatePhysics() {
const D = state.diameterMeters;
const RPM = state.rpm;
const freqHz = RPM / 60;
const omega = 2 * Math.PI * freqHz;
const speedMs = Math.PI * D * freqHz;
const speedKmh = speedMs * 3.6;
const speedMmin = speedMs * 60;
const speedMph = speedMs * 2.23694;
const R = D / 2;
let centripetalAccel = 0;
if (R > 0) {
centripetalAccel = (speedMs * speedMs) / R;
}
const centripetalG = centripetalAccel / 9.80665;
return {
freqHz,
omega,
speedMs,
speedKmh,
speedMmin,
speedMph,
centripetalG
};
}
function updateOutputs() {
const physics = calculatePhysics();
txtFrequency.innerText = physics.freqHz.toFixed(2) + ' Hz';
txtAngularSpeed.innerText = physics.omega.toFixed(1) + ' rad/s';
if (physics.centripetalG > 100000) {
txtCentripetalG.innerText = physics.centripetalG.toExponential(3) + ' G';
} else {
txtCentripetalG.innerText = physics.centripetalG.toLocaleString('ko-KR', { maximumFractionDigits: 1 }) + ' G';
}
txtGaugePrimaryValue.innerText = physics.speedMs.toLocaleString('ko-KR', { maximumFractionDigits: 2 });
txtOverlayVectorVal.innerText = physics.speedMs.toFixed(2) + ' m/s';
if (txtMs) txtMs.innerText = physics.speedMs.toLocaleString('ko-KR', { maximumFractionDigits: 2 }) + ' m/s';
txtKmh.innerText = physics.speedKmh.toLocaleString('ko-KR', { maximumFractionDigits: 1 }) + ' km/h';
txtMmin.innerText = physics.speedMmin.toLocaleString('ko-KR', { maximumFractionDigits: 0 }) + ' m/min';
txtMph.innerText = physics.speedMph.toLocaleString('ko-KR', { maximumFractionDigits: 1 }) + ' mph';
const cardMs = document.getElementById('card-ms');
if (cardMs) {
if (physics.speedMs > 100) {
cardMs.style.boxShadow = '0 0 20px rgba(219, 39, 119, 0.2)';
cardMs.style.borderColor = 'rgba(219, 39, 119, 0.4)';
} else {
cardMs.style.boxShadow = '';
cardMs.style.borderColor = '';
}
}
const maxGaugeSpeed = 100;
const percentage = Math.min(physics.speedMs / maxGaugeSpeed, 1);
const dashoffset = 251.2 * (1 - percentage);
if (gaugeProgress) {
gaugeProgress.style.strokeDashoffset = dashoffset;
if (physics.speedMs > 80) {
gaugeProgress.style.stroke = '#db2777';
gaugeProgress.style.filter = 'drop-shadow(0px 0px 8px rgba(255, 0, 127, 0.7))';
} else {
gaugeProgress.style.stroke = '#0284c7';
gaugeProgress.style.filter = 'drop-shadow(0px 0px 6px rgba(0, 242, 254, 0.6))';
}
}
}
function syncDiameterInputFromSlider() {
const val = parseFloat(sliderDiameter.value);
inputDiameter.value = val;
const config = unitConfigs[state.currentUnit];
state.diameterMeters = config.toMeters(val);
clearActivePresets();
updateOutputs();
}
function syncDiameterSliderFromInput() {
let val = parseFloat(inputDiameter.value);
if (isNaN(val) || val <= 0) val = 0.001;
const config = unitConfigs[state.currentUnit];
const sliderConfig = config.slider;
sliderDiameter.min = sliderConfig.min;
sliderDiameter.max = sliderConfig.max;
sliderDiameter.step = sliderConfig.step;
sliderDiameter.value = Math.min(Math.max(val, sliderConfig.min), sliderConfig.max);
state.diameterMeters = config.toMeters(val);
clearActivePresets();
updateOutputs();
}
function syncRpmInputFromSlider() {
const val = parseInt(sliderRpm.value);
inputRpm.value = val;
state.rpm = val;
clearActivePresets();
updateOutputs();
}
function syncRpmSliderFromInput() {
let val = parseFloat(inputRpm.value);
if (isNaN(val) || val < 0) val = 0;
if (val > sliderRpm.max) {
sliderRpm.max = Math.ceil(val * 1.2);
} else if (val < 8000) {
if (sliderRpm.max > 8000) {
sliderRpm.max = 8000;
}
}
sliderRpm.value = val;
state.rpm = val;
clearActivePresets();
updateOutputs();
}
function handleUnitChange() {
const oldUnit = state.currentUnit;
const newUnit = selectUnit.value;
state.currentUnit = newUnit;
const configNew = unitConfigs[newUnit];
labelDiameterUnit.innerText = configNew.label;
sliderDiameter.min = configNew.slider.min;
sliderDiameter.max = configNew.slider.max;
sliderDiameter.step = configNew.slider.step;
const convertedVal = configNew.fromMeters(state.diameterMeters);
inputDiameter.value = Number(convertedVal.toFixed(3));
sliderDiameter.value = Math.min(Math.max(convertedVal, configNew.slider.min), configNew.slider.max);
updateOutputs();
}
function loadPreset(presetKey) {
const preset = presets[presetKey];
if (!preset) return;
presetButtons.forEach(btn => {
if (btn.dataset.preset === presetKey) {
btn.classList.add('active');
} else {
btn.classList.remove('active');
}
});
state.diameterMeters = preset.diameter;
state.rpm = preset.rpm;
state.currentUnit = preset.unit;
selectUnit.value = preset.unit;
labelDiameterUnit.innerText = preset.unit;
const config = unitConfigs[preset.unit];
sliderDiameter.min = config.slider.min;
sliderDiameter.max = config.slider.max;
sliderDiameter.step = config.slider.step;
const uiDiameterVal = config.fromMeters(preset.diameter);
inputDiameter.value = Number(uiDiameterVal.toFixed(4));
sliderDiameter.value = uiDiameterVal;
if (preset.rpm > sliderRpm.max) {
sliderRpm.max = Math.ceil(preset.rpm * 1.1);
}
inputRpm.value = preset.rpm;
sliderRpm.value = preset.rpm;
updateOutputs();
}
function clearActivePresets() {
presetButtons.forEach(btn => btn.classList.remove('active'));
}
class SparkParticle {
constructor(x, y, angle, linearSpeed) {
this.x = x;
this.y = y;
const speedFactor = Math.min(linearSpeed * 0.08, 4) + Math.random() * 1.5;
const directionAngle = angle + (Math.random() - 0.5) * 0.25;
this.vx = Math.cos(directionAngle) * speedFactor;
this.vy = Math.sin(directionAngle) * speedFactor;
this.size = Math.random() * 1.5 + 0.5;
this.maxLife = Math.random() * 15 + 15;
this.life = this.maxLife;
const colors = ['#ffe600', '#ff8400', '#ff007f', '#ffffff'];
this.color = colors[Math.floor(Math.random() * colors.length)];
}
update() {
this.vx *= 0.95;
this.vy *= 0.95;
this.vy += 0.08;
this.x += this.vx;
this.y += this.vy;
this.life--;
}
draw(c) {
const alpha = this.life / this.maxLife;
c.save();
c.globalAlpha = alpha;
c.beginPath();
c.arc(this.x, this.y, this.size, 0, Math.PI * 2);
c.fillStyle = this.color;
c.shadowBlur = 4;
c.shadowColor = this.color;
c.fill();
c.restore();
}
}
function animate(currentTime) {
requestAnimationFrame(animate);
let dt = (currentTime - state.lastTime) / 1000;
if (isNaN(dt) || dt < 0 || dt > 1.0) {
dt = 0.016;
}
state.lastTime = currentTime;
const width = canvas.width / (window.devicePixelRatio || 1);
const height = canvas.height / (window.devicePixelRatio || 1);
const cx = width / 2;
const cy = height / 2;
ctx.clearRect(0, 0, width, height);
ctx.save();
ctx.strokeStyle = 'rgba(2, 132, 199, 0.06)';
ctx.lineWidth = 1;
for (let x = 0; x < width; x += 30) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}
for (let y = 0; y < height; y += 30) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}
ctx.restore();
const physics = calculatePhysics();
if (isNaN(physics.omega)) physics.omega = 0;
if (isNaN(physics.speedMs)) physics.speedMs = 0;
if (state.isPlaying) {
if (state.rpm > 0) {
let clampedDt = Math.min(dt, 0.1);
if (isNaN(clampedDt) || clampedDt < 0) clampedDt = 0.016;
const maxVisualOmega = 12;
const visualOmega = maxVisualOmega * (1 - Math.exp(-physics.omega / maxVisualOmega));
state.angle += state.direction * (isNaN(visualOmega) ? 0 : visualOmega) * clampedDt;
}
}
if (state.showParticles) {
if (state.isPlaying) {
if (state.rpm > 0) {
const emissionRate = Math.min(Math.floor(physics.speedMs / 12) + 1, 4);
const visualRadius = getVisualRadius();
for (let i = 0; i < emissionRate; i++) {
if (Math.random() > 0.6) {
let emitAngle = Math.random() * Math.PI * 2;
if (physics.speedMs > 150) {
emitAngle = Math.PI / 4 + (Math.random() - 0.5) * 0.15;
}
const ex = cx + Math.cos(emitAngle) * visualRadius;
const ey = cy + Math.sin(emitAngle) * visualRadius;
const tangAngle = emitAngle + (state.direction * Math.PI / 2);
state.particles.push(new SparkParticle(ex, ey, tangAngle, physics.speedMs));
}
}
}
}
}
state.particles = state.particles.filter(p => p.life > 0);
state.particles.forEach(p => {
p.update();
p.draw(ctx);
});
ctx.save();
ctx.translate(cx, cy);
const drawRadius = getVisualRadius();
displayVisualScaleText(physics.speedMs);
if (isNaN(state.angle)) {
state.angle = 0;
}
ctx.rotate(state.angle);
ctx.shadowBlur = 10;
ctx.shadowColor = 'rgba(0, 242, 254, 0.4)';
ctx.beginPath();
ctx.arc(0, 0, drawRadius, 0, Math.PI * 2);
ctx.strokeStyle = 'rgba(0, 0, 0, 0.05)';
ctx.lineWidth = 6;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, drawRadius - 3, 0, Math.PI * 2);
ctx.strokeStyle = 'rgba(0, 242, 254, 0.55)';
ctx.lineWidth = 2;
ctx.stroke();
ctx.shadowBlur = 0;
const spokesCount = 8;
for (let i = 0; i < spokesCount; i++) {
const spokeAngle = (i * Math.PI * 2) / spokesCount;
ctx.save();
ctx.rotate(spokeAngle);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, drawRadius - 10);
ctx.strokeStyle = i % 2 === 0 ? 'rgba(0, 242, 254, 0.4)' : 'rgba(138, 43, 226, 0.4)';
ctx.lineWidth = i % 2 === 0 ? 4 : 2;
ctx.stroke();
ctx.beginPath();
ctx.moveTo(-4, drawRadius - 12);
ctx.lineTo(4, drawRadius - 12);
ctx.strokeStyle = 'rgba(15, 23, 42, 0.15)';
ctx.lineWidth = 2;
ctx.stroke();
ctx.restore();
}
ctx.beginPath();
ctx.arc(0, 0, drawRadius * 0.45, 0, Math.PI * 2);
ctx.strokeStyle = 'rgba(138, 43, 226, 0.25)';
ctx.lineWidth = 1;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, 16, 0, Math.PI * 2);
ctx.fillStyle = '#ffffff';
ctx.strokeStyle = '#0284c7';
ctx.lineWidth = 3;
ctx.shadowBlur = 8;
ctx.shadowColor = '#0284c7';
ctx.fill();
ctx.stroke();
ctx.shadowBlur = 0;
ctx.beginPath();
ctx.arc(0, 0, 6, 0, Math.PI * 2);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.restore();
ctx.save();
ctx.translate(cx, cy);
const config = unitConfigs[state.currentUnit];
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, -drawRadius);
ctx.strokeStyle = 'rgba(16, 185, 129, 0.5)';
ctx.lineWidth = 1.5;
ctx.setLineDash([4, 4]);
ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = '#10b981';
ctx.font = 'bold 10px Inter';
ctx.textAlign = 'right';
const uiRadVal = config.fromMeters(state.diameterMeters / 2);
ctx.fillText(`반경 r = ${uiRadVal.toLocaleString('ko-KR', { maximumFractionDigits: 2 })} ${state.currentUnit}`, -8, -drawRadius / 2);
const dimAngle = -45 * Math.PI / 180;
const dx = Math.cos(dimAngle) * drawRadius;
const dy = Math.sin(dimAngle) * drawRadius;
ctx.beginPath();
ctx.moveTo(-dx, -dy);
ctx.lineTo(dx, dy);
ctx.strokeStyle = 'rgba(0, 242, 254, 0.45)';
ctx.lineWidth = 1.2;
ctx.stroke();
function drawArrowhead(c, x, y, angle) {
c.save();
c.translate(x, y);
c.rotate(angle);
c.beginPath();
c.moveTo(0, 0);
c.lineTo(-8, -3.5);
c.lineTo(-8, 3.5);
c.closePath();
c.fillStyle = 'rgba(0, 242, 254, 0.7)';
c.fill();
c.restore();
}
drawArrowhead(ctx, dx, dy, dimAngle);
drawArrowhead(ctx, -dx, -dy, dimAngle + Math.PI);
const uiDiamVal = config.fromMeters(state.diameterMeters);
const diamText = `지름 D = ${uiDiamVal.toLocaleString('ko-KR', { maximumFractionDigits: 2 })} ${state.currentUnit}`;
ctx.save();
ctx.translate(dx * 0.35, dy * 0.35);
ctx.rotate(dimAngle);
ctx.fillStyle = '#0284c7';
ctx.font = 'bold 10px Inter';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(diamText, 0, 0);
ctx.restore();
if (state.rpm > 0) {
const arcRadius = 34;
ctx.beginPath();
const startAngle = state.direction > 0 ? -Math.PI * 0.75 : -Math.PI * 0.25;
const endAngle = state.direction > 0 ? -Math.PI * 0.25 : -Math.PI * 0.75;
ctx.arc(0, 0, arcRadius, startAngle, endAngle, state.direction < 0);
ctx.strokeStyle = '#7c3aed';
ctx.lineWidth = 2.5;
ctx.shadowBlur = 6;
ctx.shadowColor = '#7c3aed';
ctx.stroke();
ctx.shadowBlur = 0;
const tipAngle = state.direction > 0 ? endAngle : endAngle;
ctx.save();
ctx.translate(Math.cos(tipAngle) * arcRadius, Math.sin(tipAngle) * arcRadius);
ctx.rotate(tipAngle + (state.direction > 0 ? Math.PI / 2 : -Math.PI / 2));
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(-6, -3);
ctx.lineTo(-6, 3);
ctx.closePath();
ctx.fillStyle = '#7c3aed';
ctx.fill();
ctx.restore();
ctx.fillStyle = '#1e293b';
ctx.font = '900 10px Outfit';
ctx.textAlign = state.direction > 0 ? 'left' : 'right';
const rpmX = state.direction > 0 ? arcRadius + 8 : -(arcRadius + 8);
ctx.fillText(`${state.direction > 0 ? '↻' : '↺'} ${state.rpm.toLocaleString()} RPM`, rpmX, 4);
}
ctx.restore();
if (state.rpm > 0) {
ctx.save();
ctx.translate(cx, cy);
const arrowDir = state.direction;
const arrowStartY = -drawRadius;
ctx.beginPath();
ctx.moveTo(-120, arrowStartY);
ctx.lineTo(120, arrowStartY);
ctx.strokeStyle = 'rgba(15, 23, 42, 0.12)';
ctx.lineWidth = 1;
ctx.setLineDash([3, 3]);
ctx.stroke();
ctx.setLineDash([]);
const arrowLength = Math.min(physics.speedMs * 1.3 + 25, 170);
ctx.shadowBlur = 12;
ctx.shadowColor = '#db2777';
ctx.strokeStyle = '#db2777';
ctx.fillStyle = '#db2777';
ctx.lineWidth = 4.5;
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(0, arrowStartY);
ctx.lineTo(arrowDir * arrowLength, arrowStartY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(arrowDir * arrowLength, arrowStartY);
ctx.lineTo(arrowDir * (arrowLength - 10), arrowStartY - 6);
ctx.lineTo(arrowDir * (arrowLength - 10), arrowStartY + 6);
ctx.closePath();
ctx.fill();
ctx.shadowBlur = 4;
ctx.shadowColor = '#db2777';
ctx.fillStyle = '#db2777';
ctx.beginPath();
ctx.arc(0, arrowStartY, 5, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
ctx.fillStyle = '#0f172a';
ctx.font = 'bold 11px Inter';
ctx.textAlign = arrowDir > 0 ? 'left' : 'right';
const vectorLabel = `선속도 v = ${physics.speedMs.toFixed(2)} m/s`;
ctx.fillText(
vectorLabel,
arrowDir * (arrowLength / 2),
arrowStartY - 12
);
ctx.restore();
}
ctx.save();
const scaleMeters = getNiceScaleStep(state.diameterMeters / 3.5);
if (scaleMeters > 0) {
const scaleBarPx = scaleMeters / (state.diameterMeters / (drawRadius * 2));
const startX = 20;
const startY = height - 20;
ctx.strokeStyle = 'rgba(15, 23, 42, 0.35)';
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.moveTo(startX, startY - 4);
ctx.lineTo(startX, startY);
ctx.lineTo(startX + scaleBarPx, startY);
ctx.lineTo(startX + scaleBarPx, startY - 4);
ctx.stroke();
const uiScaleVal = config.fromMeters(scaleMeters);
let displayScaleText = `${uiScaleVal.toLocaleString('ko-KR', { maximumFractionDigits: 2 })} ${state.currentUnit}`;
ctx.fillStyle = 'rgba(15, 23, 42, 0.6)';
ctx.font = 'bold 9px Inter';
ctx.textAlign = 'left';
ctx.fillText(displayScaleText, startX + 4, startY - 6);
ctx.fillStyle = 'rgba(15, 23, 42, 0.6)'; ctx.fillStyle = 'rgba(15, 23, 42, 0.6)'; ctx.fillText("SCALE", startX + scaleBarPx + 8, startY + 3);
}
ctx.restore();
}
function getVisualRadius() {
const D = state.diameterMeters;
const minVal = 0.01;
const maxVal = 2.0;
const dpr = window.devicePixelRatio || 1;
const height = canvas.height / dpr;
const maxRadius = height / 2 - 60;
const minRadius = Math.max(50, height / 6);
if (D <= minVal) return minRadius;
if (D >= maxVal) return maxRadius;
const pct = (D - minVal) / (maxVal - minVal);
return minRadius + pct * (maxRadius - minRadius);
}
function displayVisualScaleText(speedMs) {
const D = state.diameterMeters;
let text = '화면 스케일: ';
if (D < 0.01) {
text += `마이크로 (1:${(0.1 / D).toFixed(0)} 비율)`;
} else if (D < 1) {
text += `밀리미터급`;
} else if (D < 10) {
text += `인체/자전거급 (1:1 실제 비율)`;
} else if (D < 1000) {
text += `항공기/터빈급 (축소 출력)`;
} else {
text += `행성 스케일 (초고도 축소)`;
}
txtCanvasScale.innerText = text;
}
function getNiceScaleStep(approxVal) {
if (approxVal <= 0) return 0;
const exponent = Math.floor(Math.log10(approxVal));
const fraction = approxVal / Math.pow(10, exponent);
let step;
if (fraction < 1.5) step = 1;
else if (fraction < 3.5) step = 2;
else if (fraction < 7.5) step = 5;
else step = 10;
return step * Math.pow(10, exponent);
}
sliderDiameter.addEventListener('input', syncDiameterInputFromSlider);
inputDiameter.addEventListener('change', syncDiameterSliderFromInput);
inputDiameter.addEventListener('input', syncDiameterSliderFromInput);
sliderRpm.addEventListener('input', syncRpmInputFromSlider);
inputRpm.addEventListener('change', syncRpmSliderFromInput);
inputRpm.addEventListener('input', syncRpmSliderFromInput);
selectUnit.addEventListener('change', handleUnitChange);
btnPlayPause.addEventListener('click', () => {
state.isPlaying = !state.isPlaying;
if (state.isPlaying) {
btnPlayPause.innerHTML = '<i class="fa-solid fa-pause"></i> <span>일시정지</span>';
btnPlayPause.classList.remove('active');
} else {
btnPlayPause.innerHTML = '<i class="fa-solid fa-play"></i> <span>재생</span>';
btnPlayPause.classList.add('active');
}
});
btnReverse.addEventListener('click', () => {
state.direction *= -1;
btnReverse.classList.add('press-glow');
setTimeout(() => btnReverse.classList.remove('press-glow'), 300);
});
btnParticles.addEventListener('click', () => {
state.showParticles = !state.showParticles;
if (state.showParticles) {
btnParticles.classList.add('active');
} else {
btnParticles.classList.remove('active');
}
});
presetButtons.forEach(btn => {
btn.addEventListener('click', () => {
const key = btn.dataset.preset;
loadPreset(key);
});
});
loadPreset('bicycle');
requestAnimationFrame(animate);
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
return false;
}, { capture: true });
document.addEventListener('selectstart', function(e) {
e.preventDefault();
return false;
}, { capture: true });
document.addEventListener('keydown', function(e) {
if (e.key === 'F12') {
e.preventDefault();
alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
return false;
}
if (e.ctrlKey) {
if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
e.preventDefault();
alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
return false;
}
if (e.shiftKey) {
if (['i','I','j','J','c','C'].includes(e.key)) {
e.preventDefault();
alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
return false;
}
}
}
}, { capture: true });
}
let initAttempts = 0;
function tryInit() {
initAttempts++;
initRotaspeed();
if (!window.__rotaspeed_initialized) {
if (initAttempts < 50) {
setTimeout(tryInit, 100);
}
}
}
if (document.readyState === 'complete' || document.readyState === 'interactive') {
tryInit();
} else {
document.addEventListener('DOMContentLoaded', tryInit);
window.addEventListener('load', tryInit);
}
})();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>회전체 지름 입력: 슬라이더를 조절하거나 우측 숫자 입력 칸에 회전체의 실제 지름을 입력합니다. (기본 mm단위, cm/m/inch로 단위 변환 지원)</strong></li>
<li style="margin-bottom: 6px;">회전수(RPM) 입력: 아래 슬라이더 또는 숫자 칸에 분당 회전 속도를 직접 타이핑하여 설정합니다.</li>
<li style="margin-bottom: 6px;">실시간 수치 판독: 지름과 RPM을 변경하면 실시간으로 계산된 선속도 파티클 효과와 물리 벡터 화살표가 바뀌며, 실시간 수치(m/s, km/h, m/min) 및 원심 가속도를 확인합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 기계공학 해설 및 설계 규격 (KS/ISO) 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 선끝속도(Linear Tip Speed)의 정의 및 공학적 중요성</h3>
<p>선끝속도(접선 속도, Tangential Speed)는 회전하는 강체의 가장 바깥쪽 표면상 한 점이 가지는 순간적인 선형 속도를 의미합니다. 기계공학 및 기계설계 분야에서 선끝속도는 부품의 내구성, 소음, 마찰열, 그리고 가공 정밀도를 결정짓는 극한의 핵심 설계 인자입니다. 대표적으로 원주속도(Peripheral Speed) 혹은 주속이라고도 불리며, 다음과 같은 시스템에서 임계 설계 기준으로 작용합니다.</p><ul><li><strong>절삭가공 (선삭 및 밀링):</strong> 공구 끝단의 절삭 속도(Cutting Speed)가 최적의 범위를 벗어나면 공구 마모가 급격히 촉진되거나 조도가 저하됩니다.</li><li><strong>회전체 역학 (플라이휠, 터빈 플래터):</strong> 고속 회전 시 원심력에 의한 인장 응력이 선끝속도의 제곱에 비례하여 증가하므로 파손 방지를 위한 강도학적 한계 검토가 반드시 필요합니다.</li><li><strong>동력 전달 (풀리, 체인):</strong> 마찰전동 및 물림전동에서 슬립(Slip) 방지 및 소음 임계치 설계를 위해 적정 속도 제어가 요구됩니다.</li></ul>
<h3>2. 핵심 수학적 기초 및 계산 공식 유도</h3>
<p>원운동을 하는 입자의 각속도를 <code>&omega;</code> (rad/s), 회전 반경을 <code>R</code> (m)이라고 하면 접선 방향의 선속도 <code>v</code> (m/s)는 다음과 같이 각속도와 반경의 곱으로 표현됩니다:</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">v = R &times; &omega;</p><p>실무 설계 및 현장 계산에서는 각속도 대신 초당 회전수 또는 분당 회전수(RPM, N)와 지름(D, mm)을 주로 사용하므로 공식 변환이 이루어집니다. 각속도 <code>&omega;</code>는 1회전이 <code>2&pi;</code> 라디안이므로 다음과 같이 유도됩니다:</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">&omega; = (2&pi; &times; N) / 60</p><p>이를 반경 <code>R = D / 2</code>와 미터 단위 변환(1m = 1000mm)을 적용하여 종합하면 최종적인 선끝속도 공학 계산 공식이 도출됩니다:</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.1em; color: #0369a1;">v = (&pi; &times; D &times; N) / (60 &times; 1000) = (&pi; &times; D &times; N) / 60,000 &nbsp;[m/s]</p>
<h3>3. 연관 물리량: 원심가속도 및 원심력</h3>
<p>선끝속도가 증가할 때 회전하는 부품 내부에 발생하는 응력을 분석하기 위해서는 원심가속도(Centripetal Acceleration) <code>a_c</code>를 반드시 고려해야 합니다:</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">a_c = v^2 / R = R &times; &omega;^2 &nbsp;[m/s^2]</p><p>원심가속도는 속도의 제곱에 비례하기 때문에 회전 지름보다 회전 속도(RPM)가 미치는 영향이 지배적입니다. 이는 회전체의 질량이 <code>m</code>일 때 관성력인 원심력(Centrifugal Force) <code>F_c = m &times; a_c</code>로 이어지며, 고속 스핀들이나 연삭 숫돌의 파손(Bursting) 설계에 있어 안전계수 결정의 결정적인 척도가 됩니다.</p>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/linear-tip-speed-simulator-calculator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>벨트-풀리 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/belt-pulley-speed-calculator-simulator-2/</link>
					<comments>https://myengnote.com/belt-pulley-speed-calculator-simulator-2/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[동력전달]]></category>
		<category><![CDATA[물리시뮬레이터]]></category>
		<category><![CDATA[벨트계산기]]></category>
		<category><![CDATA[벨트풀리]]></category>
		<guid isPermaLink="false">https://myengnote.com/belt-pulley-speed-calculator-simulator-2/</guid>

					<description><![CDATA[두 풀리의 지름, 축간거리, 입력 RPM을 조절하여 벨트 길이, 접촉각, 벨트 속도 및 출력 속도를 실시간 계산하고 부드럽게 구동되는 벨트 전동 시스템을 시각화하는 초정밀 2D 시뮬레이터입니다.]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 벨트-풀리 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for beltpulley-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .beltpulley-calculator-wrapper *, .beltpulley-calculator-wrapper *::before, .beltpulley-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .beltpulley-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7;
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777;
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .beltpulley-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.15;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.12; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.22; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-muted));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: #0284c7; }
        .text-magenta { color: #db2777; }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .helper-text {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within {
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 8px 0;
            transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        /* D1 Webkit Thumb */
        #slider-d1::-webkit-slider-thumb {
            background: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan);
        }
        #slider-d1::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-cyan), 0 0 5px #fff;
        }
        /* D1 Firefox Thumb */
        #slider-d1::-moz-range-thumb {
            width: 18px;
            height: 18px;
            border: none;
            border-radius: 50%;
            background: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan);
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-d1::-moz-range-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-cyan), 0 0 5px #fff;
        }
        /* D2 Webkit Thumb */
        #slider-d2::-webkit-slider-thumb {
            background: var(--color-magenta);
            box-shadow: 0 0 10px var(--color-magenta);
        }
        #slider-d2::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-magenta), 0 0 5px #fff;
        }
        /* D2 Firefox Thumb */
        #slider-d2::-moz-range-thumb {
            width: 18px;
            height: 18px;
            border: none;
            border-radius: 50%;
            background: var(--color-magenta);
            box-shadow: 0 0 10px var(--color-magenta);
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-d2::-moz-range-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-magenta), 0 0 5px #fff;
        }
        /* C (Center Distance) Webkit Thumb */
        #slider-c::-webkit-slider-thumb {
            background: #ffffff;
            box-shadow: 0 0 10px var(--color-cyan);
        }
        #slider-c::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-cyan), 0 0 5px #fff;
        }
        /* C (Center Distance) Firefox Thumb */
        #slider-c::-moz-range-thumb {
            width: 18px;
            height: 18px;
            border: none;
            border-radius: 50%;
            background: #ffffff;
            box-shadow: 0 0 10px var(--color-cyan);
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-c::-moz-range-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-cyan), 0 0 5px #fff;
        }
        /* RPM Webkit Thumb */
        #slider-rpm::-webkit-slider-thumb {
            background: var(--color-purple);
            box-shadow: 0 0 10px var(--color-purple);
        }
        #slider-rpm::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-purple), 0 0 5px #fff;
        }
        /* RPM Firefox Thumb */
        #slider-rpm::-moz-range-thumb {
            width: 18px;
            height: 18px;
            border: none;
            border-radius: 50%;
            background: var(--color-purple);
            box-shadow: 0 0 10px var(--color-purple);
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-rpm::-moz-range-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-purple), 0 0 5px #fff;
        }
        .control-actions {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-top: 10px;
        }
        .presets-section {
            display: flex;
            flex-direction: column;
            gap: 12px;
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: grid;
            grid-template-columns: 1fr;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            border-color: var(--color-border);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: #0284c7;
            transition: all 0.2s ease;
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
            box-shadow: var(--shadow-neon-cyan);
        }
        .preset-name {
            font-size: 12px;
            font-weight: 600;
            letter-spacing: 0.25px;
        }
        .simulation-panel {
            grid-column: 2;
            align-self: start;
            justify-content: flex-start;
            min-width: 0;
        }
        .simulation-panel .panel-header {
            justify-content: space-between;
        }
        .canvas-scale-indicator {
            font-size: 11px;
            color: var(--color-text-muted);
            background: rgba(0, 0, 0, 0.02);
            padding: 4px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
        }
        .canvas-wrapper {
            position: relative;
            width: 100%;
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%);
            border: 1px solid rgba(0, 0, 0, 0.06);
            border-radius: 16px;
            overflow: hidden;
        }
        #physics-canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 16 / 10;
        }
        .canvas-overlay-data {
            position: absolute;
            top: 16px;
            left: 16px;
            pointer-events: none;
            display: flex;
            flex-direction: column;
            gap: 6px;
        }
        .overlay-item {
            background: transparent;
            color: var(--color-text-main);
            padding: 4px 0;
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: 11px;
        }
        .overlay-item .label {
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .overlay-item .value {
            font-weight: 700;
        }
        .simulation-metrics-strip {
            display: flex;
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 20px;
            justify-content: space-around;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
        }
        .mini-metric {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 4px;
            text-align: center;
        }
        .mini-metric .label {
            font-size: 10px;
            font-weight: 600;
            color: var(--color-text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        .mini-metric .value {
            font-size: 14px;
            font-weight: 700;
            color: var(--color-text-main);
            font-family: var(--font-heading);
        }
        .mini-divider {
            width: 1px;
            height: 24px;
            background: rgba(0, 0, 0, 0.03);
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(0, 242, 254, 0.08) 0%, rgba(138, 43, 226, 0.03) 100%);
            border: 1px solid rgba(0, 242, 254, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            box-shadow: 0 0 15px rgba(0, 242, 254, 0.05);
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: #0284c7;
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 26px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .ratio-type {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85); box-shadow: 0 2px 8px rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(0, 242, 254, 0.2);
            background: rgba(0, 242, 254, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
            transition: all 0.2s ease;
        }
        .result-card:hover .card-icon {
            color: #0284c7;
            border-color: rgba(0, 242, 254, 0.3);
            background: rgba(0, 242, 254, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 17px;
            color: var(--color-text-main);
        }
        .formula-card {
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            font-size: 12px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        .formula-equation {
            font-family: monospace;
            color: #0284c7;
            font-size: 13px;
            background: #f8fafc; border-color: var(--color-border);
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        /* Container Query for Responsiveness inside WP */
        @container beltpulley-container (max-width: 1024px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.beltpulley-calculator-wrapper .app-main-grid,
.beltpulley-calculator-wrapper .main-grid,
.beltpulley-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.beltpulley-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.beltpulley-calculator-wrapper .simulation-panel,
.beltpulley-calculator-wrapper .canvas-panel,
.beltpulley-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.beltpulley-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.beltpulley-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.beltpulley-calculator-wrapper .simulation-results-section .ratio-readout-box,
.beltpulley-calculator-wrapper .simulation-results-section .re-readout-box,
.beltpulley-calculator-wrapper .simulation-results-section .status-readout-box,
.beltpulley-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.beltpulley-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.beltpulley-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.beltpulley-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .beltpulley-calculator-wrapper .app-main-grid,
    .beltpulley-calculator-wrapper .main-grid,
    .beltpulley-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .beltpulley-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .beltpulley-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .beltpulley-calculator-wrapper .simulation-panel,
    .beltpulley-calculator-wrapper .canvas-panel,
    .beltpulley-calculator-wrapper .sim-panel,
    .beltpulley-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .beltpulley-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .beltpulley-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .beltpulley-calculator-wrapper .simulation-results-section .re-readout-box,
    .beltpulley-calculator-wrapper .simulation-results-section .status-readout-box,
    .beltpulley-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .beltpulley-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .beltpulley-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.beltpulley-calculator-wrapper .app-container,
.beltpulley-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.beltpulley-calculator-wrapper .simulation-results-section .formula-card,
.beltpulley-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 8px !important;
}
.beltpulley-calculator-wrapper .simulation-results-section .formula-card h4,
.beltpulley-calculator-wrapper .results-panel .formula-card h4 {
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
}
.beltpulley-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="beltpulley-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-circle-nodes"></i></div>
                <div>
                    <h1>BELT DRIVE</h1>
                    <div class="subtitle">벨트-풀리 속도 계산기 &#038; 2D 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">2D PHYSICS ENGINE ACTIVE</div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>시뮬레이션 제어 변수</h2>
                </div>
                <!-- Pulley 1 Diameter D1 -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-circle text-cyan"></i> 구동 풀리 지름 (D₁)</label>
                        <span class="helper-text">구동측 (50 ~ 600 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-d1" class="custom-number-input" min="50" max="600" value="100">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-d1" class="custom-slider" min="50" max="600" value="100">
                </div>
                <!-- Pulley 2 Diameter D2 -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-circle text-magenta"></i> 피동 풀리 지름 (D₂)</label>
                        <span class="helper-text">피동측 (50 ~ 600 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-d2" class="custom-number-input" min="50" max="600" value="200">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-d2" class="custom-slider" min="50" max="600" value="200">
                </div>
                <!-- Center Distance C -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-arrows-left-right"></i> 축간 중심거리 (C)</label>
                        <span class="helper-text">축간거리 (최소 ~ 1200 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-c" class="custom-number-input" min="200" max="1200" value="450">
                        <div class="unit-badge">mm</div>
                    </div>
                    <input type="range" id="slider-c" class="custom-slider" min="200" max="1200" value="450">
                </div>
                <!-- Input RPM N1 -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-gauge-high text-purple"></i> 입력 회전수 (N₁)</label>
                        <span class="helper-text">입력 속도 (0 ~ 2500 RPM)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-rpm" class="custom-number-input" min="0" max="2500" value="240">
                        <div class="unit-badge">RPM</div>
                    </div>
                    <input type="range" id="slider-rpm" class="custom-slider" min="0" max="2500" value="240">
                </div>
                <!-- Simulation Controls -->
                <div class="control-actions">
                    <button id="btn-play-pause" class="action-btn">
                        <i class="fa-solid fa-pause"></i> <span>일시정지</span>
                    </button>
                    <button id="btn-reverse" class="action-btn">
                        <i class="fa-solid fa-backward"></i> <span>방향 전환</span>
                    </button>
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3><i class="fa-solid fa-tags text-cyan"></i> 벨트-풀리 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn" data-preset="reduction">
                            <div class="preset-icon"><i class="fa-solid fa-down-long"></i></div>
                            <div class="preset-details"><span class="preset-name">2:1 V벨트 감속 시스템</div>
                        </button>
                        <button class="preset-btn" data-preset="mesh1to1">
                            <div class="preset-icon"><i class="fa-solid fa-left-right"></i></div>
                            <div class="preset-name">1:1 등속 동력 전달</div>
                        </button>
                        <button class="preset-btn" data-preset="increase">
                            <div class="preset-icon"><i class="fa-solid fa-up-long"></i></div>
                            <div class="preset-name">1:3 기계식 증속 전동</div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <div style="display: flex; align-items: center; gap: 12px;">
                                        <i class="fa-solid fa-circle-nodes text-cyan"></i>
                                        <h2>실시간 벨트 주행 물리 뷰</h2>
                                    </div>
                                    <div id="txt-canvas-scale" class="canvas-scale-indicator">스케일 자동 조정</div>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas"></canvas>
                                    <!-- Overlay Floating Data -->
                                    <div class="canvas-overlay-data">
                                        <div class="overlay-item">
                                            <span class="label">총 벨트 길이 (L):</span>
                                            <span class="value text-cyan" id="txt-belt-length-overlay">0.0 mm</span>
                                        </div>
                                    </div>
                                </div>
                                <!-- Mini Metrics -->
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <div class="label">구동 풀리 접촉각</span><span class="preset-spec">θ₁</span></div>
                                        <div id="txt-lap-angle1" class="value">0.0°</div>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <div class="label">피동 풀리 접촉각 (θ₂)</div>
                                        <div id="txt-lap-angle2" class="value">0.0°</div>
                                    </div>
                                </div>
                                <!-- Integrated Results Analysis Section -->
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                            <div class="ratio-title">최종 풀리 배율 (i)</div>
                                            <div id="txt-pulley-ratio" class="ratio-value">2.00 : 1</div>
                                            <div id="txt-ratio-type" class="ratio-type">2.00배 감속 전동</div>
                                        </div>
                                <div class="results-grid">
                                        <!-- Belt Pitch Speed -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-gauge-simple text-cyan"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">벨트 주속도 (v)</span>
                                                <span id="txt-belt-speed" class="card-value">0.0 m/s</span>
                                            </div>
                                        </div>
                                        <!-- Pulley 2 Output Speed -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-rotate text-magenta"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">피동 풀리 회전수 (N₂)</span>
                                                <span id="txt-n2" class="card-value">0.0 RPM</span>
                                            </div>
                                        </div>
                                        <!-- Calculated Belt Length -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-ruler-horizontal text-purple"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">계산된 표준 벨트 길이 (L)</span>
                                                <span id="txt-belt-length" class="card-value">0.0 mm</span>
                                            </div>
                                        </div>
                                        <!-- Torque Factor -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-bolt text-success"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">출력 토크 변환율 (T₂/T₁)</span>
                                                <span id="txt-torque-mult" class="card-value">100%</span>
                                            </div>
                                        </div>
                                    </div>
                                <div class="formula-card">
                                            <h4><i class="fa-solid fa-circle-info text-cyan"></i> 벨트 전동 공학식</h4>
                                            <div class="formula-equation">
                                                L ≈ 2C + π(D₁+D₂)/2 + (D₂-D₁)²/4C
                                            </div>
                                            <div class="formula-equation">
                                                θ₁ = π &#8211; 2·sin⁻¹((D₂-D₁)/2C)
                                            </div>
                                        </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- Physics & Animation Engine -->
    </div>
</div>
<script>
        (function() {
        let isBeltInit = false;
        function initBeltSimulator() {
            if (isBeltInit) return;
            const canvas = document.getElementById('physics-canvas');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            if (!ctx) return;
            isBeltInit = true;
            window.__beltpulley_initialized = true;
            // DOM Elements
            const sliderD1 = document.getElementById('slider-d1');
            const inputD1 = document.getElementById('input-d1');
            const sliderD2 = document.getElementById('slider-d2');
            const inputD2 = document.getElementById('input-d2');
            const sliderC = document.getElementById('slider-c');
            const inputC = document.getElementById('input-c');
            const sliderRpm = document.getElementById('slider-rpm');
            const inputRpm = document.getElementById('input-rpm');
            const btnPlayPause = document.getElementById('btn-play-pause');
            const btnReverse = document.getElementById('btn-reverse');
            const presetButtons = document.querySelectorAll('.preset-btn');
            const txtCenterDistOverlay = document.getElementById('txt-belt-length-overlay');
            const txtLapAngle1 = document.getElementById('txt-lap-angle1');
            const txtLapAngle2 = document.getElementById('txt-lap-angle2');
            const txtPulleyRatio = document.getElementById('txt-pulley-ratio');
            const txtRatioType = document.getElementById('txt-ratio-type');
            const txtBeltSpeed = document.getElementById('txt-belt-speed');
            const txtN2 = document.getElementById('txt-n2');
            const txtBeltLength = document.getElementById('txt-belt-length');
            const txtTorqueMult = document.getElementById('txt-torque-mult');
            const wrapper = document.querySelector('.beltpulley-calculator-wrapper') || document.body;
            // State variables
            const state = {
                d1: 100,
                d2: 200,
                c: 450,
                rpm: 240,
                angle1: 0,
                angle2: 0,
                beltOffset: 0,
                isPlaying: true,
                direction: 1,
                lastTime: 0,
                sparks: []
            };
            // Canvas Resizing (Retina support)
            function resizeCanvas() {
                const rect = canvas.getBoundingClientRect();
                const dpr = window.devicePixelRatio || 1;
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            resizeCanvas();
            window.addEventListener('resize', resizeCanvas);
            setTimeout(resizeCanvas, 300);
            // Friction sparks at tangent points
            class BeltSpark {
                constructor(x, y, vx, vy) {
                    this.x = x;
                    this.y = y;
                    this.vx = vx;
                    this.vy = vy;
                    this.size = Math.random() * 1.5 + 0.5;
                    this.life = Math.random() * 20 + 8;
                    this.maxLife = this.life;
                    const colors = ['#00f2fe', '#ff007f', '#ffffff'];
                    this.color = colors[Math.floor(Math.random() * colors.length)];
                }
                update() {
                    this.x += this.vx;
                    this.y += this.vy;
                    this.vx *= 0.96;
                    this.vy *= 0.96;
                    this.life--;
                }
                draw(c) {
                    const alpha = this.life / this.maxLife;
                    c.save();
                    c.globalAlpha = alpha;
                    c.beginPath();
                    c.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                    c.fillStyle = this.color;
                    c.fill();
                    c.restore();
                }
            }
            // Sync Inputs and Sliders
            function syncD1FromSlider() {
                const val = parseInt(sliderD1.value);
                inputD1.value = val;
                state.d1 = val;
                validateCenterDistance();
                clearPresets();
                updateCalculations();
            }
            function syncD1FromInput() {
                let val = parseInt(inputD1.value);
                if (isNaN(val) || val < 50) val = 50;
                if (val > 600) val = 600;
                sliderD1.value = val;
                state.d1 = val;
                validateCenterDistance();
                clearPresets();
                updateCalculations();
            }
            function syncD2FromSlider() {
                const val = parseInt(sliderD2.value);
                inputD2.value = val;
                state.d2 = val;
                validateCenterDistance();
                clearPresets();
                updateCalculations();
            }
            function syncD2FromInput() {
                let val = parseInt(inputD2.value);
                if (isNaN(val) || val < 50) val = 50;
                if (val > 600) val = 600;
                sliderD2.value = val;
                state.d2 = val;
                validateCenterDistance();
                clearPresets();
                updateCalculations();
            }
            function syncCFromSlider() {
                const val = parseInt(sliderC.value);
                inputC.value = val;
                state.c = val;
                validateCenterDistance();
                clearPresets();
                updateCalculations();
            }
            function syncCFromInput() {
                let val = parseInt(inputC.value);
                if (isNaN(val) || val < 200) val = 200;
                if (val > 1200) val = 1200;
                sliderC.value = val;
                state.c = val;
                validateCenterDistance();
                clearPresets();
                updateCalculations();
            }
            function syncRpmFromSlider() {
                const val = parseInt(sliderRpm.value);
                inputRpm.value = val;
                state.rpm = val;
                clearPresets();
                updateCalculations();
            }
            function syncRpmFromInput() {
                let val = parseInt(inputRpm.value);
                if (isNaN(val) || val < 0) val = 0;
                if (val > 2500) val = 2500;
                sliderRpm.value = val;
                state.rpm = val;
                clearPresets();
                updateCalculations();
            }
            // Ensure center distance is physically larger than radius1 + radius2 to avoid overlap
            function validateCenterDistance() {
                const minC = (state.d1 + state.d2) / 2 + 30; // 30mm margin
                if (state.c < minC) {
                    state.c = Math.ceil(minC);
                    inputC.value = state.c;
                    sliderC.value = state.c;
                }
                // Set slider range dynamically
                sliderC.min = Math.ceil(minC);
                if (parseInt(inputC.value) < minC) {
                    inputC.value = Math.ceil(minC);
                    sliderC.value = Math.ceil(minC);
                    state.c = Math.ceil(minC);
                }
            }
            // Physics Core Calculations
            function updateCalculations() {
                const D1 = state.d1;
                const D2 = state.d2;
                const C = state.c;
                const N1 = state.rpm;
                // 1. Pulley Ratio
                const ratio = D2 / D1;
                txtPulleyRatio.innerText = ratio.toFixed(2) + ' : 1';
                if (ratio > 1) {
                    txtRatioType.innerText = `${ratio.toFixed(2)}배 감속 전동 (출력 토크 ${ratio.toFixed(2)}배)`;
                } else if (ratio < 1) {
                    const gain = 1 / ratio;
                    txtRatioType.innerText = `${gain.toFixed(2)}배 증속 전동 (출력 토크 ${ratio.toFixed(2)}배)`;
                } else {
                    txtRatioType.innerText = '1:1 동속 동력 전동';
                }
                // 2. Output RPM
                const n2 = N1 / ratio;
                txtN2.innerText = n2.toFixed(1) + ' RPM';
                txtTorqueMult.innerText = (ratio * 100).toFixed(0) + '%';
                // 3. Pitch line velocity (Belt Speed in m/s)
                const pitchSpeed = (Math.PI * D1 * N1) / 60000;
                txtBeltSpeed.innerText = pitchSpeed.toFixed(2) + ' m/s';
                // 4. Belt Length calculation
                const term1 = 2 * C;
                const term2 = (Math.PI * (D1 + D2)) / 2;
                const term3 = Math.pow(D2 - D1, 2) / (4 * C);
                const beltLen = term1 + term2 + term3;
                txtBeltLength.innerText = beltLen.toFixed(1) + ' mm';
                txtCenterDistOverlay.innerText = beltLen.toFixed(1) + ' mm';
                // 5. Lap angles
                // sin(alpha) = (D2 - D1) / 2C
                const sinAlpha = (D2 - D1) / (2 * C);
                const alpha = Math.asin(Math.min(Math.max(sinAlpha, -0.99), 0.99));
                const angle1Rad = Math.PI - 2 * alpha;
                const angle2Rad = Math.PI + 2 * alpha;
                const angle1Deg = (angle1Rad * 180) / Math.PI;
                const angle2Deg = (angle2Rad * 180) / Math.PI;
                txtLapAngle1.innerText = angle1Deg.toFixed(1) + '°';
                txtLapAngle2.innerText = angle2Deg.toFixed(1) + '°';
                if (angle1Deg < 120) {
                    txtLapAngle1.style.color = '#db2777';
                } else {
                    txtLapAngle1.style.color = '#10b981';
                }
            }
            // Presets Click Handler
            function loadPreset(key) {
                clearPresets();
                presetButtons.forEach(btn => {
                    if (btn.dataset.preset === key) {
                        btn.classList.add('active');
                    }
                });
                if (key === 'reduction') {
                    state.d1 = 120;
                    state.d2 = 240;
                    state.c = 480;
                    state.rpm = 300;
                } else if (key === 'mesh1to1') {
                    state.d1 = 180;
                    state.d2 = 180;
                    state.c = 450;
                    state.rpm = 200;
                } else if (key === 'increase') {
                    state.d1 = 240;
                    state.d2 = 80;
                    state.c = 450;
                    state.rpm = 100;
                }
                // Sync inputs
                inputD1.value = state.d1;
                sliderD1.value = state.d1;
                inputD2.value = state.d2;
                sliderD2.value = state.d2;
                inputC.value = state.c;
                sliderC.value = state.c;
                inputRpm.value = state.rpm;
                sliderRpm.value = state.rpm;
                validateCenterDistance();
                updateCalculations();
            }
            function clearPresets() {
                presetButtons.forEach(btn => btn.classList.remove('active'));
            }
            // Draw Pulley Wheel
            function drawPulley(c, x, y, radius, angle, themeColor) {
                c.save();
                c.translate(x, y);
                // 1. Pulley Outer Body (dark glass fill)
                c.beginPath();
                c.arc(0, 0, radius, 0, Math.PI * 2);
                c.fillStyle = 'rgba(241, 245, 249, 0.85)';
                c.fill();
                c.strokeStyle = themeColor;
                c.lineWidth = 3;
                c.shadowBlur = 8;
                c.shadowColor = themeColor;
                c.stroke();
                c.shadowBlur = 0;
                // 2. Pulley Inner Rim Ring
                c.beginPath();
                c.arc(0, 0, radius - 6, 0, Math.PI * 2);
                c.strokeStyle = 'rgba(15, 23, 42, 0.06)';
                c.lineWidth = 1.5;
                c.stroke();
                // 3. Rotating Spokes
                c.save();
                c.rotate(angle);
                // Central hub
                const hubRad = Math.max(radius * 0.25, 12);
                c.beginPath();
                c.arc(0, 0, hubRad, 0, Math.PI * 2);
                c.strokeStyle = 'rgba(15, 23, 42, 0.15)';
                c.lineWidth = 2;
                c.stroke();
                c.beginPath();
                c.arc(0, 0, 5, 0, Math.PI * 2);
                c.fillStyle = '#ffffff';
                c.fill();
                // 5 spokes
                const spokes = 5;
                for (let s = 0; s < spokes; s++) {
                    const spokeAngle = (s * 2 * Math.PI) / spokes;
                    c.save();
                    c.rotate(spokeAngle);
                    c.beginPath();
                    c.moveTo(0, hubRad);
                    c.lineTo(0, radius - 8);
                    c.strokeStyle = 'rgba(15, 23, 42, 0.08)';
                    c.lineWidth = 3;
                    c.stroke();
                    c.restore();
                }
                // Keyway marker (to see rotation clearly)
                c.beginPath();
                c.arc(radius - 12, 0, 4, 0, Math.PI * 2);
                c.fillStyle = '#ffffff';
                c.shadowBlur = 4;
                c.shadowColor = '#ffffff';
                c.fill();
                c.restore();
                c.restore();
            }
            function drawDiameterLeader(c, x, y, r, valStr, labelPrefix, side) {
                c.save();
                c.strokeStyle = 'rgba(71, 85, 105, 0.4)';
                c.lineWidth = 1.2;
                // Angle of leader line (45 degrees up-left or up-right)
                const angle = side === -1 ? -Math.PI * 0.75 : -Math.PI * 0.25;
                const px = x + Math.cos(angle) * r;
                const py = y + Math.sin(angle) * r;
                // Draw a beautiful small dot on the circle boundary
                c.beginPath();
                c.arc(px, py, 2.5, 0, Math.PI * 2);
                c.fillStyle = side === -1 ? '#0284c7' : '#db2777';
                c.fill();
                // Draw leader lines: from circle boundary diagonal outwards, then horizontal
                const lx1 = px + Math.cos(angle) * 20;
                const ly1 = py + Math.sin(angle) * 20;
                const lx2 = lx1 + side * 45;
                const ly2 = ly1;
                c.beginPath();
                c.moveTo(px, py);
                c.lineTo(lx1, ly1);
                c.lineTo(lx2, ly2);
                c.stroke();
                // Draw text above the horizontal line
                const text = `${labelPrefix} ${valStr}`;
                c.font = 'bold 10px var(--font-body)';
                const tx = side === -1 ? lx1 - 4 : lx1 + 4;
                c.fillStyle = '#1e293b';
                c.textAlign = side === -1 ? 'right' : 'left';
                c.textBaseline = 'bottom';
                c.fillText(text, tx, ly2 - 1);
                c.restore();
            }
            // Main Animation Frame
            function animate(currentTime) {
                requestAnimationFrame(animate);
                let dt = (currentTime - state.lastTime) / 1000;
                if (isNaN(dt) || dt < 0 || dt > 1.0) dt = 0.016;
                state.lastTime = currentTime;
                const width = canvas.width / (window.devicePixelRatio || 1);
                const height = canvas.height / (window.devicePixelRatio || 1);
                const cx = width / 2;
                const cy = height / 2;
                ctx.clearRect(0, 0, width, height);
                // 1. Draw Grid
                ctx.save();
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.06)';
                ctx.lineWidth = 1;
                for (let x = 0; x < width; x += 30) {
                    ctx.beginPath();
                    ctx.moveTo(x, 0);
                    ctx.lineTo(x, height);
                    ctx.stroke();
                }
                for (let y = 0; y < height; y += 30) {
                    ctx.beginPath();
                    ctx.moveTo(0, y);
                    ctx.lineTo(width, y);
                    ctx.stroke();
                }
                ctx.restore();
                // 2. Geometry Scale Calculation
                const phys_r1 = state.d1 / 2;
                const phys_r2 = state.d2 / 2;
                const scaleWidth = (width - 190) / (state.c + phys_r1 + phys_r2);
                const scaleHeight = (height - 120) / Math.max(state.d1, state.d2);
                const scale = Math.min(scaleWidth, scaleHeight);
                const txtCanvasScale = document.getElementById('txt-canvas-scale');
                if (txtCanvasScale) {
                    txtCanvasScale.innerText = `스케일 비율: 1:${(1/scale * 100).toFixed(0)}급`;
                }
                const r1 = phys_r1 * scale;
                const r2 = phys_r2 * scale;
                const c_vis = state.c * scale;
                // Position centers to perfectly center the entire bounding box
                const x1 = (width - c_vis + r1 - r2) / 2;
                const y1 = cy;
                const x2 = x1 + c_vis;
                const y2 = cy;
                // Physics Rotation
                const ratio = state.d2 / state.d1;
                const pitchSpeed = (Math.PI * state.d1 * state.rpm) / 60000; // m/s
                if (state.isPlaying) {
                    if (state.rpm > 0) {
                        const omega1 = (2 * Math.PI * state.rpm) / 60; // rad/s
                        // Stroboscopic rendering limit
                        const maxOmega = 6;
                        const renderOmega1 = maxOmega * (1 - Math.exp(-omega1 / maxOmega));
                        state.angle1 += state.direction * renderOmega1 * dt;
                        state.angle2 += state.direction * (renderOmega1 / ratio) * dt;
                        // Linear belt move offset
                        state.beltOffset += state.direction * pitchSpeed * 1000 * scale * dt;
                    }
                }
                // 3. Tangent belt geometry calculations
                const dx = x2 - x1;
                const alpha = Math.asin((r2 - r1) / dx);
                // Tangent angles relative to horizontal
                const theta_top1 = -Math.PI / 2 - alpha;
                const theta_bottom1 = Math.PI / 2 + alpha;
                const theta_top2 = -Math.PI / 2 - alpha;
                const theta_bottom2 = Math.PI / 2 + alpha;
                // Tangent Points on Pulley 1
                const tp1_top_x = x1 + r1 * Math.cos(theta_top1);
                const tp1_top_y = y1 + r1 * Math.sin(theta_top1);
                const tp1_bottom_x = x1 + r1 * Math.cos(theta_bottom1);
                const tp1_bottom_y = y1 + r1 * Math.sin(theta_bottom1);
                // Tangent Points on Pulley 2
                const tp2_top_x = x2 + r2 * Math.cos(theta_top2);
                const tp2_top_y = y2 + r2 * Math.sin(theta_top2);
                const tp2_bottom_x = x2 + r2 * Math.cos(theta_bottom2);
                const tp2_bottom_y = y2 + r2 * Math.sin(theta_bottom2);
                // 4. Spawn Friction Sparks at Tangent Points
                if (state.isPlaying) {
                    if (state.rpm > 300) {
                        const sparkEmission = Math.min(Math.floor(state.rpm / 600) + 1, 2);
                        for (let s = 0; s < sparkEmission; s++) {
                            if (Math.random() > 0.6) {
                                // Top tangent left sparks
                                const spVx = -state.direction * (2 + Math.random() * 2);
                                const spVy = (Math.random() - 0.5) * 1.5;
                                state.sparks.push(new BeltSpark(tp1_top_x, tp1_top_y, spVx * scale, spVy * scale));
                            }
                        }
                    }
                }
                // Render Sparks
                state.sparks = state.sparks.filter(s => s.life > 0);
                state.sparks.forEach(s => {
                    s.update();
                    s.draw(ctx);
                });
                // 5. Draw Pulley 1 (Drive - Cyan)
                drawPulley(ctx, x1, y1, r1, state.angle1, '#0284c7');
                // Draw Pulley 2 (Driven - Magenta)
                drawPulley(ctx, x2, y2, r2, state.angle2, '#db2777');
                // 6. Draw Snug Belt Around both pulleys (Moving dashed line)
                ctx.save();
                ctx.beginPath();
                // Top tangent line
                ctx.moveTo(tp1_top_x, tp1_top_y);
                ctx.lineTo(tp2_top_x, tp2_top_y);
                // Clockwise arc around Pulley 2
                ctx.arc(x2, y2, r2, theta_top2, theta_bottom2, false);
                // Bottom tangent line
                ctx.lineTo(tp1_bottom_x, tp1_bottom_y);
                // Clockwise arc around Pulley 1
                ctx.arc(x1, y1, r1, theta_bottom1, theta_top1, false);
                ctx.closePath();
                // Belt outer shadow/glow
                ctx.shadowBlur = 12;
                ctx.shadowColor = '#0284c7';
                ctx.strokeStyle = '#0284c7';
                ctx.lineWidth = 7;
                ctx.lineCap = 'round';
                ctx.lineJoin = 'round';
                ctx.stroke();
                ctx.shadowBlur = 0;
                // Moving belt textured interior dashes
                ctx.strokeStyle = '#ffffff';
                ctx.lineWidth = 5;
                ctx.setLineDash([16, 12]);
                ctx.lineDashOffset = -state.beltOffset;
                ctx.stroke();
                ctx.setLineDash([]);
                ctx.restore();
                // 7. Dimension annotations
                ctx.save();
                // Draw Diameter dimensions on pulleys with professional CAD leader lines
                drawDiameterLeader(ctx, x1, y1, r1, state.d1.toFixed(1) + ' mm', 'd₁ =', -1);
                drawDiameterLeader(ctx, x2, y2, r2, state.d2.toFixed(1) + ' mm', 'd₂ =', 1);
                // Horizontal Center Distance Dimension Line (C)
                ctx.save();
                ctx.strokeStyle = 'rgba(71, 85, 105, 0.3)';
                ctx.lineWidth = 1;
                const dimY = y1 + r2 + 25; // 25px below larger pulley
                ctx.beginPath();
                ctx.moveTo(x1, y1 + 10);
                ctx.lineTo(x1, dimY + 5);
                ctx.moveTo(x2, y2 + 10);
                ctx.lineTo(x2, dimY + 5);
                ctx.stroke();
                ctx.beginPath();
                ctx.moveTo(x1, dimY);
                ctx.lineTo(x2, dimY);
                ctx.stroke();
                function drawHorizontalArrowhead(px, py, direction) {
                    ctx.save();
                    ctx.translate(px, py);
                    ctx.fillStyle = 'rgba(71, 85, 105, 0.5)';
                    ctx.beginPath();
                    ctx.moveTo(0, 0);
                    ctx.lineTo(direction * 6, -3);
                    ctx.lineTo(direction * 6, 3);
                    ctx.closePath();
                    ctx.fill();
                    ctx.restore();
                }
                drawHorizontalArrowhead(x1, dimY, 1);
                drawHorizontalArrowhead(x2, dimY, -1);
                const cText = `C = ${state.c} mm`;
                ctx.font = 'bold 9px Inter, sans-serif';
                const cTextWidth = ctx.measureText(cText).width;
                const cTextX = (x1 + x2) / 2;
                // Draw white eraser background so text doesn't overlap dimension line
                ctx.fillStyle = '#f1f5f9';
                ctx.fillRect(cTextX - cTextWidth / 2 - 4, dimY - 6, cTextWidth + 8, 12);
                ctx.fillStyle = '#475569';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.fillText(cText, cTextX, dimY);
                ctx.restore();
                // Lap angle highlights (colored arcs representing wrap contact)
                ctx.beginPath();
                ctx.arc(x1, y1, r1 + 10, theta_bottom1, theta_top1, false);
                ctx.strokeStyle = 'rgba(0, 242, 254, 0.35)';
                ctx.lineWidth = 3;
                ctx.stroke();
                ctx.beginPath();
                ctx.arc(x2, y2, r2 + 10, theta_top2, theta_bottom2, false);
                ctx.strokeStyle = 'rgba(255, 0, 127, 0.35)';
                ctx.lineWidth = 3;
                ctx.stroke();
                ctx.restore();
            }
            // Bind Event Listeners
            sliderD1.addEventListener('input', syncD1FromSlider);
            inputD1.addEventListener('change', syncD1FromInput);
            sliderD2.addEventListener('input', syncD2FromSlider);
            inputD2.addEventListener('change', syncD2FromInput);
            sliderC.addEventListener('input', syncCFromSlider);
            inputC.addEventListener('change', syncCFromInput);
            sliderRpm.addEventListener('input', syncRpmFromSlider);
            inputRpm.addEventListener('change', syncRpmFromInput);
            btnPlayPause.addEventListener('click', () => {
                state.isPlaying = !state.isPlaying;
                if (state.isPlaying) {
                    btnPlayPause.innerHTML = '<i class="fa-solid fa-pause"></i> <span>일시정지</span>';
                } else {
                    btnPlayPause.innerHTML = '<i class="fa-solid fa-play"></i> <span>재생</span>';
                }
            });
            btnReverse.addEventListener('click', () => {
                state.direction *= -1;
            });
            presetButtons.forEach(btn => {
                btn.addEventListener('click', () => {
                    loadPreset(btn.dataset.preset);
                });
            });
            // Initialize
            loadPreset('reduction');
            requestAnimationFrame(animate);
            // ── 우클릭 & 소스 복사 방지 (전체 문서 레벨 + 알림창 동기화) ──
            document.addEventListener('contextmenu', function(e) {
                e.preventDefault();
                alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                return false;
            }, { capture: true });
            document.addEventListener('selectstart', function(e) {
                e.preventDefault();
                return false;
            }, { capture: true });
            // 개발자도구 단축키 및 복사 단축키 차단 (F12, Ctrl+U, Ctrl+Shift+I/J/C, Ctrl+C, Ctrl+S)
            // 중복 차단 문자를 사용하면 WordPress API에서 오류가 날 수 있으므로 nested if로 구현
            document.addEventListener('keydown', function(e) {
                if (e.key === 'F12') {
                    e.preventDefault();
                    alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                    return false;
                }
                if (e.ctrlKey) {
                    if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
                        e.preventDefault();
                        alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                        return false;
                    }
                    if (e.shiftKey) {
                        if (['i','I','j','J','c','C'].includes(e.key)) {
                            e.preventDefault();
                            alert("이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.");
                            return false;
                        }
                    }
                }
            }, { capture: true });
        } // <-- Closed the initBeltSimulator function
        // Robust ReadyState hook-up with polling to guarantee execution even if DOM elements load late
        let initAttempts = 0;
        function tryInit() {
            initAttempts++;
            initBeltSimulator();
            if (!window.__beltpulley_initialized) {
                if (initAttempts < 50) {
                    setTimeout(tryInit, 100);
                }
            }
        }
        if (document.readyState === 'complete' || document.readyState === 'interactive') {
            tryInit();
        } else {
            document.addEventListener('DOMContentLoaded', tryInit);
            window.addEventListener('load', tryInit);
        }
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>풀리 지름 설정: 슬라이더나 입력 칸을 이용해 구동 풀리(D₁)와 피동 풀리(D₂)의 외경 지름을 입력합니다.</strong></li>
<li style="margin-bottom: 6px;">축간거리 및 입력 속도 설정: 두 풀리 축 사이의 중심거리(C)와 구동 풀리의 RPM(N₁)을 설정합니다.</li>
<li style="margin-bottom: 6px;">실시간 벨트 구동 관찰: 회전 속도에 맞춰 벨트라인이 부드럽게 움직이는 2D 물리 시뮬레이션을 관찰합니다.</li>
<li style="margin-bottom: 6px;">출력 계측치 분석: 총 벨트 길이(L), 풀리별 접촉각(Lap Angle), 벨트 선속도(m/s) 및 피동 풀리 속도(RPM)를 계측 모니터에서 즉시 분석합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 기계공학 해설 및 벨트 전동 설계 규격 (KS/ISO) 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 벨트 전동(Belt Drive)의 기본 원리 및 공학적 특징</h3>
<p>벨트 전동은 두 개 이상의 풀리(Pulley)에 유연한 벨트(Belt)를 감아 마찰력 또는 물림력에 의해 동력을 전달하는 대표적인 유연 전동 장치(Flexible Transmitter)입니다. 기어 전동에 비해 축간 거리가 먼 경우에 경제적으로 동력을 전달할 수 있으며, 충격 흡수 성능이 우수하고 운전이 비교적 조용하다는 큰 장점을 지니고 있습니다.</p><ul><li><strong>평벨트 (Flat Belt):</strong> 고속 운전에 적합하며 굴곡성이 좋으나 슬립(Slip)이 발생하기 쉽습니다.</li><li><strong>V벨트 (V-Belt):</strong> 홈과의 쐐기 작용(Wedge Action)에 의한 마찰력 증대로 비교적 큰 토크를 슬립 없이 전달할 수 있어 산업용 동력 전달에 가장 널리 쓰입니다.</li><li><strong>타이밍 벨트 (Timing Belt/정밀 물림 벨트):</strong> 기어처럼 치형이 형성되어 슬립률 0%의 동기 전동(Synchronous Drive)이 가능합니다.</li></ul>
<h3>2. 벨트 길이 및 접촉각 수학적 유도 공식</h3>
<p>벨트 전동 설계의 기본이 되는 기하학적 치수와 역학적 관계식은 다음과 같이 유도됩니다.</p><p><strong>① 평행 벨트 길이 계산 공식 (Open Belt Length):</strong> 두 풀리의 지름을 <code>D1</code>, <code>D2</code>, 축간거리를 <code>C</code>라고 할 때, 기하학적 궤적을 적분하여 얻어지는 표준 근사식입니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">L &approx; 2C + &pi;(D1 + D2)/2 + (D2 - D1)^2 / (4C) &nbsp;[mm]</p><p><strong>② 접촉각 (Lap Angle / 접촉 호의 각도, &theta;):</strong> 동력 전달 용량을 결정하는 가장 중요한 인자 중 하나로, 구동 풀리에서의 접촉각 <code>&theta;1</code>이 작을수록 슬립 현상이 일어나기 쉽습니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">&theta;1 = &pi; - 2 &times; sin^(-1)((D2 - D1) / 2C) &nbsp;[rad]</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">&theta;2 = &pi; + 2 &times; sin^(-1)((D2 - D1) / 2C) &nbsp;[rad]</p><p><strong>③ 벨트의 주속도 (Belt Pitch Line Speed, v):</strong> 동력이 전달되는 벨트의 선형 주행 속도로, 구동 풀리 기준 공식은 다음과 같습니다:</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.05em; color: #0369a1;">v = (&pi; &times; D1 &times; N1) / 60,000 &nbsp;[m/s]</p>
<h3>3. 마찰 전동의 오일러 공식 (슬립 및 장력 설계)</h3>
<p>벨트가 풀리에 감겨 회전할 때, 미끄러지기 직전의 긴장측 장력(Tight Side Tension, <code>T_t</code>)과 이완측 장력(Slack Side Tension, <code>T_s</code>)의 비율은 벨트와 풀리 사이의 마찰 계수(<code>&mu;</code>)와 접촉각(<code>&theta;</code>)에 의해 지수적으로 결정됩니다. 이를 **오일러의 벨트 공식(Euler's Belt Formula)**이라고 합니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">T_t / T_s = e^(&mu; &times; &theta;)</p><p>이 식은 접촉각 <code>&theta;</code>가 클수록 장력비가 기하급수적으로 증가하여 더 큰 유효 인장력(<code>F_e = T_t - T_s</code>)을 전달할 수 있음을 입증합니다. 따라서 소형 풀리의 접촉각이 120&deg; 이하로 떨어지는 감속 비율이 큰 설계에서는 아이들러 풀리(Idler Pulley)를 추가 장착하여 이완측 접촉각을 강제로 확보하는 보정 설계가 필수로 작용합니다.</p>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/belt-pulley-speed-calculator-simulator-2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>기어비 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/gear-ratio-calculator-simulator-3/</link>
					<comments>https://myengnote.com/gear-ratio-calculator-simulator-3/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Tue, 26 May 2026 00:00:00 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[기어계산기]]></category>
		<category><![CDATA[기어비]]></category>
		<category><![CDATA[동력전달]]></category>
		<category><![CDATA[물리시뮬레이터]]></category>
		<guid isPermaLink="false">https://myengnote.com/gear-ratio-calculator-simulator-3/</guid>

					<description><![CDATA[기어 잇수와 입력 RPM을 조절하여 기어비, 출력 속도, 토크 변화 및 기하학적 치수를 실시간으로 계산하고 완벽히 맞물려 회전하는 기어열을 시각화하는 초정밀 2D 물리 시뮬레이터입니다.]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 기어비 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for gearratio-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .gearratio-calculator-wrapper *, .gearratio-calculator-wrapper *::before, .gearratio-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .gearratio-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7;
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777;
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .gearratio-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.15;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.12; }
            100% { transform: scale(1.2) translate(50px, 50px); opacity: 0.22; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-muted));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .fa-spin-slow {
            animation: fa-spin 15s linear infinite;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr 340px;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: #0284c7; }
        .text-magenta { color: #db2777; }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .helper-text {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within {
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 8px 0;
            transition: background 0.2s ease;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.1s ease, box-shadow 0.2s ease;
        }
        #slider-z1::-webkit-slider-thumb {
            background: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan);
        }
        #slider-z1::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-cyan), 0 0 5px #fff;
        }
        #slider-z2::-webkit-slider-thumb {
            background: var(--color-magenta);
            box-shadow: 0 0 10px var(--color-magenta);
        }
        #slider-z2::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-magenta), 0 0 5px #fff;
        }
        #slider-rpm::-webkit-slider-thumb {
            background: var(--color-purple);
            box-shadow: 0 0 10px var(--color-purple);
        }
        #slider-rpm::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 0 15px var(--color-purple), 0 0 5px #fff;
        }
        .control-actions {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-top: 10px;
        }
        .action-btn {
            background: rgba(0, 0, 0, 0.02);
            border: 1px solid var(--color-border);
            color: var(--color-text-main);
            padding: 10px;
            border-radius: 10px;
            font-size: 12px;
            font-weight: 600;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
        }
        .action-btn:hover {
            background: rgba(0, 0, 0, 0.03);
            border-color: var(--color-border);
        }
        .action-btn.active {
            background: var(--color-cyan-glow);
            border-color: #0284c7;
            color: #0284c7;
            box-shadow: 0 0 12px var(--color-cyan-glow);
        }
        .presets-section {
            display: flex;
            flex-direction: column;
            gap: 12px;
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: grid;
            grid-template-columns: 1fr;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            border-color: var(--color-border);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: #0284c7;
            transition: all 0.2s ease;
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
            box-shadow: var(--shadow-neon-cyan);
        }
        .preset-name {
            font-size: 12px;
            font-weight: 600;
            letter-spacing: 0.25px;
        }
        .simulation-panel {
            grid-column: 2;
            align-self: start;
            justify-content: flex-start;
            min-width: 0;
        }
        .simulation-panel .panel-header {
            justify-content: space-between;
        }
        .canvas-scale-indicator {
            font-size: 11px;
            color: var(--color-text-muted);
            background: rgba(0, 0, 0, 0.02);
            padding: 4px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
        }
        .canvas-wrapper {
            position: relative;
            width: 100%;
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%);
            border: 1px solid rgba(0, 0, 0, 0.06);
            border-radius: 16px;
            overflow: hidden;
        }
        #physics-canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 16 / 10;
        }
        .canvas-overlay-data {
            position: absolute;
            top: 16px;
            left: 16px;
            pointer-events: none;
            display: flex;
            flex-direction: column;
            gap: 6px;
        }
        .overlay-item {
            background: transparent;
            color: var(--color-text-main);
            padding: 4px 0;
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: 11px;
        }
        .overlay-item .label {
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .overlay-item .value {
            font-weight: 700;
        }
        .simulation-metrics-strip {
            display: flex;
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 20px;
            justify-content: space-around;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
        }
        .mini-metric {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 4px;
            text-align: center;
        }
        .mini-metric .label {
            font-size: 10px;
            font-weight: 600;
            color: var(--color-text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        .mini-metric .value {
            font-size: 14px;
            font-weight: 700;
            color: var(--color-text-main);
            font-family: var(--font-heading);
        }
        .mini-divider {
            width: 1px;
            height: 24px;
            background: rgba(0, 0, 0, 0.03);
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(0, 242, 254, 0.08) 0%, rgba(138, 43, 226, 0.03) 100%);
            border: 1px solid rgba(0, 242, 254, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            box-shadow: 0 0 15px rgba(0, 242, 254, 0.05);
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: #0284c7;
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 38px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-cyan));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .ratio-type {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85); box-shadow: 0 2px 8px rgba(0,0,0,0.03);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(0, 242, 254, 0.2);
            background: rgba(0, 242, 254, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
            transition: all 0.2s ease;
        }
        .result-card:hover .card-icon {
            color: #0284c7;
            border-color: rgba(0, 242, 254, 0.3);
            background: rgba(0, 242, 254, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-text-muted);
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 18px;
            color: var(--color-text-main);
        }
        .formula-card {
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            font-size: 12px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        .formula-equation {
            font-family: monospace;
            color: #0284c7;
            font-size: 13px;
            background: #f8fafc; border-color: var(--color-border);
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        /* Container Query for Responsiveness inside WP */
        @container gearratio-container (max-width: 1024px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
        /* Language Switcher Styles */
        .lang-switch-wrapper {
            display: flex;
            gap: 4px;
            background: rgba(0, 0, 0, 0.04);
            border: 1px solid rgba(0, 0, 0, 0.08);
            padding: 3px;
            border-radius: 8px;
        }
        .lang-btn {
            padding: 4px 8px;
            font-size: 11px;
            font-weight: 700;
            border: none;
            background: transparent;
            color: #475569 !important; /* Slate grey */
            cursor: pointer;
            border-radius: 6px;
            transition: all 0.2s;
            font-family: 'Inter', sans-serif;
        }
        .lang-btn:hover {
            color: #1e293b !important;
            background: rgba(0, 0, 0, 0.02);
        }
        .lang-btn.active {
            background: #ffffff !important;
            color: #0284c7 !important; /* Cyan active */
            box-shadow: 0 2px 4px rgba(0,0,0,0.08);
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.gearratio-calculator-wrapper .app-main-grid,
.gearratio-calculator-wrapper .main-grid,
.gearratio-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.gearratio-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.gearratio-calculator-wrapper .simulation-panel,
.gearratio-calculator-wrapper .canvas-panel,
.gearratio-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.gearratio-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.gearratio-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.gearratio-calculator-wrapper .simulation-results-section .ratio-readout-box,
.gearratio-calculator-wrapper .simulation-results-section .re-readout-box,
.gearratio-calculator-wrapper .simulation-results-section .status-readout-box,
.gearratio-calculator-wrapper .simulation-results-section .flow-readout-box,
.gearratio-calculator-wrapper .simulation-results-section [class*="readout-box"],
.gearratio-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.gearratio-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.gearratio-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.gearratio-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .gearratio-calculator-wrapper .app-main-grid,
    .gearratio-calculator-wrapper .main-grid,
    .gearratio-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .gearratio-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .gearratio-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .gearratio-calculator-wrapper .simulation-panel,
    .gearratio-calculator-wrapper .canvas-panel,
    .gearratio-calculator-wrapper .sim-panel,
    .gearratio-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .gearratio-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .gearratio-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .gearratio-calculator-wrapper .simulation-results-section .re-readout-box,
    .gearratio-calculator-wrapper .simulation-results-section .status-readout-box,
    .gearratio-calculator-wrapper .simulation-results-section .flow-readout-box,
    .gearratio-calculator-wrapper .simulation-results-section [class*="readout-box"],
    .gearratio-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .gearratio-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .gearratio-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.gearratio-calculator-wrapper .app-container,
.gearratio-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.gearratio-calculator-wrapper .simulation-results-section .formula-card,
.gearratio-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    gap: 8px !important;
}
.gearratio-calculator-wrapper .simulation-results-section .formula-card h4,
.gearratio-calculator-wrapper .results-panel .formula-card h4 {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
    margin-top: 0 !important;
    margin-bottom: 4px !important;
    word-break: keep-all !important;
    line-height: 1.4 !important;
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
}
.gearratio-calculator-wrapper .formula-equation {
    font-family: 'Outfit', 'Cambria Math', 'Times New Roman', monospace !important;
    white-space: nowrap !important;
    overflow-x: auto !important;
    word-break: keep-all !important;
    text-align: center !important;
}
.gearratio-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="gearratio-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-gear fa-spin-slow"></i></div>
                <div>
                    <h1>GEAR MESH</h1>
                    <div class="subtitle" data-i18n="header_subtitle">초정밀 기어비 시뮬레이터 &#038; 계산기</div>
                </div>
            </div>
            <div style="display: flex; align-items: center; gap: 12px;">
                <div class="lang-switch-wrapper" style="display: flex; gap: 4px; background: rgba(0, 0, 0, 0.03); border: 1px solid var(--color-border); padding: 3px; border-radius: 8px;">
                    <button class="lang-btn active" data-lang="ko" style="padding: 4px 8px; font-size: 11px; font-weight: 700; border: none; background: transparent; cursor: pointer; border-radius: 6px; transition: all 0.2s; font-family: 'Inter', sans-serif;">KO</button>
                    <button class="lang-btn" data-lang="en" style="padding: 4px 8px; font-size: 11px; font-weight: 700; border: none; background: transparent; cursor: pointer; border-radius: 6px; transition: all 0.2s; font-family: 'Inter', sans-serif;">EN</button>
                </div>
                <div class="header-badge">
                    <div class="pulse-dot"></div>
                    <div class="badge-text" data-i18n="badge_text">2D PHYSICS ENGINE ACTIVE</div>
                </div>
            </div>
        </header>
        <!-- Main Layout Grid -->
        <main class="app-main-grid">
            <!-- Left Panel: Controls -->
            <section class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2 data-i18n="panel_control_title">시뮬레이션 제어 변수</h2>
                </div>
                <!-- Input Gear Teeth Z1 -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-cog text-cyan"></i> <span data-i18n="label_z1">구동 기어 잇수 (Z₁)</span></label>
                        <span class="helper-text" data-i18n="helper_z1">구동측 (8 ~ 100 T)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-z1" class="custom-number-input" min="8" max="100" value="12">
                        <div class="unit-badge">T</div>
                    </div>
                    <input type="range" id="slider-z1" class="custom-slider" min="8" max="100" value="12">
                </div>
                <!-- Output Gear Teeth Z2 -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-cog text-magenta"></i> <span data-i18n="label_z2">피동 기어 잇수 (Z₂)</span></label>
                        <span class="helper-text" data-i18n="helper_z2">피동측 (8 ~ 100 T)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-z2" class="custom-number-input" min="8" max="100" value="24">
                        <div class="unit-badge">T</div>
                    </div>
                    <input type="range" id="slider-z2" class="custom-slider" min="8" max="100" value="24">
                </div>
                <!-- Input Speed RPM -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-gauge-high text-purple"></i> <span data-i18n="label_rpm">입력 회전수 (N₁)</span></label>
                        <span class="helper-text" data-i18n="helper_rpm">입력 속도 (0 ~ 3000 RPM)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-rpm" class="custom-number-input" min="0" max="3000" value="120">
                        <div class="unit-badge">RPM</div>
                    </div>
                    <input type="range" id="slider-rpm" class="custom-slider" min="0" max="3000" value="120">
                </div>
                <!-- Gear Module (Pitch sizing) -->
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-ruler"></i> <span data-i18n="label_module">기어 모듈 (m)</span></label>
                        <span class="helper-text" data-i18n="helper_module">이빨 크기 (1.0 ~ 8.0 mm)</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-module" class="custom-number-input" min="1.0" max="8.0" step="0.5" value="3.0">
                        <div class="unit-badge">mm</div>
                    </div>
                </div>
                <!-- Simulation Controls -->
                <div class="control-actions">
                    <button id="btn-play-pause" class="action-btn">
                        <i class="fa-solid fa-pause"></i> <span>일시정지</span>
                    </button>
                    <button id="btn-reverse" class="action-btn">
                        <i class="fa-solid fa-backward"></i> <span data-i18n="btn_reverse">방향 전환</span>
                    </button>
                </div>
                <!-- Presets -->
                <div class="presets-section">
                    <h3 data-i18n="preset_title"><i class="fa-solid fa-tags text-cyan"></i> 하이테크 기어 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn" data-preset="reduction">
                            <div class="preset-icon"><i class="fa-solid fa-arrow-down-wide-short"></i></div>
                            <div class="preset-details"><span class="preset-name" data-i18n="preset_reduction_name">4:1 강력 감속 시스템</span></div>
                        </button>
                        <button class="preset-btn" data-preset="mesh1to1">
                            <div class="preset-icon"><i class="fa-solid fa-arrows-left-right"></i></div>
                            <div class="preset-details"><span class="preset-name" data-i18n="preset_mesh_name">1:1 속도 매칭 정밀 기어</span></div>
                        </button>
                        <button class="preset-btn" data-preset="increase">
                            <div class="preset-icon"><i class="fa-solid fa-arrow-up-wide-short"></i></div>
                            <div class="preset-details"><span class="preset-name" data-i18n="preset_increase_name">1:3 기계식 증속 장치</span></div>
                        </button>
                    </div>
                </div>
            </section>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <section class="panel simulation-panel">
                                <div class="panel-header">
                                    <div style="display: flex; align-items: center; gap: 12px;">
                                        <i class="fa-solid fa-circle-nodes text-cyan"></i>
                                        <h2 data-i18n="panel_physics_title">실시간 기어 맞물림 물리 뷰</h2>
                                    </div>
                                    <div id="txt-canvas-scale" class="canvas-scale-indicator">스케일 자동 조정</div>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas"></canvas>
                                    <!-- Overlay Floating Data -->
                                    <div class="canvas-overlay-data">
                                        <div class="overlay-item">
                                            <span class="label" data-i18n="label_center_dist">축간 중심거리 C:</span>
                                            <span class="value text-cyan" id="txt-center-dist">0.0 mm</span>
                                        </div>
                                    </div>
                                </div>
                                <!-- Mini Metrics -->
                                <div class="simulation-metrics-strip">
                                    <div class="mini-metric">
                                        <div class="label" data-i18n="label_pitch_speed">선속도</div>
                                        <div id="txt-pitch-speed" class="value">0.0 m/s</div>
                                    </div>
                                    <div class="mini-divider"></div>
                                    <div class="mini-metric">
                                        <div class="label" data-i18n="label_mesh_frequency">접촉점 맞물림 진동수</div>
                                        <div id="txt-mesh-frequency" class="value">0.0 Hz</div>
                                    </div>
                                </div>
                                <!-- Integrated Results Analysis Section -->
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                    <div class="ratio-title" data-i18n="ratio_title">최종 기어비 (i)</div>
                                    <div id="txt-gear-ratio" class="ratio-value">2.00 : 1</div>
                                    <div id="txt-ratio-type" class="ratio-type">2.00배 감속 (토크 2.00배 증대)</div>
                                </div>
                                <div class="results-grid">
                                    <!-- Gear 1 Output Diameter -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-circle-dot text-cyan"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit" data-i18n="card_d1">구동 기어 피치원 지름 (d₁)</span>
                                            <span id="txt-d1" class="card-value">0.0 mm</span>
                                        </div>
                                    </div>
                                    <!-- Gear 2 Output Diameter -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-circle-dot text-magenta"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit" data-i18n="card_d2">피동 기어 피치원 지름 (d₂)</span>
                                            <span id="txt-d2" class="card-value">0.0 mm</span>
                                        </div>
                                    </div>
                                    <!-- Gear 2 Output Speed -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-rotate text-purple"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit" data-i18n="card_n2">피동 기어 속도 (N₂)</span>
                                            <span id="txt-n2" class="card-value">0.0 RPM</span>
                                        </div>
                                    </div>
                                    <!-- Torque Multiplier -->
                                    <div class="result-card">
                                        <div class="card-icon"><i class="fa-solid fa-bolt text-success"></i></div>
                                        <div class="card-content">
                                            <span class="card-unit" data-i18n="card_torque_mult">출력 토크 변환배율 (T₂/T₁)</span>
                                            <span id="txt-torque-mult" class="card-value">100% (동일)</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="formula-card">
                                    <h4 data-i18n="formula_title"><i class="fa-solid fa-circle-info text-cyan"></i> 핵심 동역학 공식</h4>
                                    <div class="formula-equation">
                                        i = Z₂ / Z₁ = N₁ / N₂
                                    </div>
                                    <div class="formula-equation">
                                        d = m × Z
                                    </div>
                                </div>
                            </div>
                </section>
            </div>
        </main>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span data-i18n="disclaimer_text"><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
    </div>
    <!-- Physics & Mesh Animation Engine -->
    </div>
</div>
<script>
        (function() {
        let isGearInit = false;
        function initGearSimulator() {
            if (isGearInit) return;
            const canvas = document.getElementById('physics-canvas');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            if (!ctx) return;
            isGearInit = true;
            window.__gearratio_initialized = true;
            // DOM Elements
            const sliderZ1 = document.getElementById('slider-z1');
            const inputZ1 = document.getElementById('input-z1');
            const sliderZ2 = document.getElementById('slider-z2');
            const inputZ2 = document.getElementById('input-z2');
            const sliderRpm = document.getElementById('slider-rpm');
            const inputRpm = document.getElementById('input-rpm');
            const inputModule = document.getElementById('input-module');
            const btnPlayPause = document.getElementById('btn-play-pause');
            const btnReverse = document.getElementById('btn-reverse');
            const presetButtons = document.querySelectorAll('.preset-btn');
            const txtCenterDist = document.getElementById('txt-center-dist');
            const txtPitchSpeed = document.getElementById('txt-pitch-speed');
            const txtMeshFrequency = document.getElementById('txt-mesh-frequency');
            const txtGearRatio = document.getElementById('txt-gear-ratio');
            const txtRatioType = document.getElementById('txt-ratio-type');
            const txtD1 = document.getElementById('txt-d1');
            const txtD2 = document.getElementById('txt-d2');
            const txtN2 = document.getElementById('txt-n2');
            const txtTorqueMult = document.getElementById('txt-torque-mult');
            const wrapper = document.querySelector('.gearratio-calculator-wrapper') || document.body;
            // State variables
            const state = {
                z1: 12,
                z2: 24,
                rpm: 120,
                m: 3.0,
                angle1: 0,
                angle2: 0,
                isPlaying: true,
                direction: 1,
                lastTime: 0,
                sparks: [],
                lang: 'ko' // Default language
            };
            // i18n Translations Dictionary
            const translations = {
                ko: {
                    header_subtitle: "초정밀 기어비 시뮬레이터 & 계산기",
                    panel_control_title: "시뮬레이션 제어 변수",
                    label_z1: "구동 기어 잇수 (Z₁)",
                    helper_z1: "구동측 (8 ~ 100 T)",
                    label_z2: "피동 기어 잇수 (Z₂)",
                    helper_z2: "피동측 (8 ~ 100 T)",
                    label_rpm: "입력 회전수 (N₁)",
                    helper_rpm: "입력 속도 (0 ~ 3000 RPM)",
                    label_module: "기어 모듈 (m)",
                    helper_module: "이빨 크기 (1.0 ~ 8.0 mm)",
                    btn_reverse: "방향 전환",
                    preset_title: "하이테크 기어 프리셋",
                    preset_reduction_name: "4:1 강력 감속 시스템",
                    preset_mesh_name: "1:1 속도 매칭 정밀 기어",
                    preset_increase_name: "1:3 기계식 증속 장치",
                    panel_physics_title: "실시간 기어 맞물림 물리 뷰",
                    label_center_dist: "축간 중심거리 C:",
                    label_pitch_speed: "선속도",
                    label_mesh_frequency: "접촉점 맞물림 진동수",
                    panel_results_title: "해석 및 정량 결과",
                    ratio_title: "최종 기어비 (i)",
                    card_d1: "구동 기어 피치원 지름 (d₁)",
                    card_d2: "피동 기어 피치원 지름 (d₂)",
                    card_n2: "피동 기어 속도 (N₂)",
                    card_torque_mult: "출력 토크 변환배율 (T₂/T₁)",
                    formula_title: "핵심 동역학 공식",
                    disclaimer_text: "<strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다."
                },
                en: {
                    header_subtitle: "Precision Gear Ratio Simulator & Calculator",
                    panel_control_title: "Simulation Control Variables",
                    label_z1: "Drive Gear Teeth (Z₁)",
                    helper_z1: "Drive side (8 ~ 100 T)",
                    label_z2: "Driven Gear Teeth (Z₂)",
                    helper_z2: "Driven side (8 ~ 100 T)",
                    label_rpm: "Input Speed (N₁)",
                    helper_rpm: "Input speed (0 ~ 3000 RPM)",
                    label_module: "Gear Module (m)",
                    helper_module: "Tooth size (1.0 ~ 8.0 mm)",
                    btn_reverse: "Reverse Direction",
                    preset_title: "High-Tech Gear Presets",
                    preset_reduction_name: "4:1 High Reduction System",
                    preset_mesh_name: "1:1 Speed Matching Precision",
                    preset_increase_name: "1:3 Mechanical Speed Increaser",
                    panel_physics_title: "Real-Time Gear Mesh Physics View",
                    label_center_dist: "Center Distance C:",
                    label_pitch_speed: "Pitch Line Speed",
                    label_mesh_frequency: "Teeth Meshing Frequency",
                    panel_results_title: "Analysis & Quantitative Results",
                    ratio_title: "Final Gear Ratio (i)",
                    card_d1: "Drive Gear Pitch Diameter (d₁)",
                    card_d2: "Driven Gear Pitch Diameter (d₂)",
                    card_n2: "Driven Gear Speed (N₂)",
                    card_torque_mult: "Output Torque Ratio (T₂/T₁)",
                    formula_title: "Key Gear Dynamics Formulas",
                    disclaimer_text: "<strong>Disclaimer:</strong> The calculations and simulations provided here are for educational and informational purposes only. Always verify with official design standards and engineering specifications before manufacturing. The author and this blog assume no liability for direct or indirect damages arising from using this tool."
                }
            };
            function applyLanguage(lang) {
                state.lang = lang;
                document.querySelectorAll('[data-i18n]').forEach(elem => {
                    const key = elem.getAttribute('data-i18n');
                    if ((translations[lang]) ? (translations[lang][key]) : false) {
                        elem.innerHTML = translations[lang][key];
                    }
                });
                // Update language buttons active state
                document.querySelectorAll('.lang-btn').forEach(btn => {
                    if (btn.dataset.lang === lang) {
                        btn.classList.add('active');
                        btn.style.background = '#ffffff';
                        btn.style.color = 'var(--color-cyan)';
                        btn.style.boxShadow = '0 2px 4px rgba(0,0,0,0.05)';
                    } else {
                        btn.classList.remove('active');
                        btn.style.background = 'transparent';
                        btn.style.color = 'var(--color-text-muted)';
                        btn.style.boxShadow = 'none';
                    }
                });
                // Refresh dynamic text values
                updateCalculations();
                // Refresh play/pause button text
                const btnPlayPauseSpan = btnPlayPause.querySelector('span');
                if (btnPlayPauseSpan) {
                    btnPlayPauseSpan.innerText = state.isPlaying 
                        ? (lang === 'ko' ? '일시정지' : 'Pause')
                        : (lang === 'ko' ? '재생' : 'Play');
                }
            }
            // Language detect & Initialization (Robust detection)
            const urlParams = new URLSearchParams(window.location.search);
            let detectedLang = urlParams.get('lang');
            if (!detectedLang) {
                const path = window.location.pathname;
                if (path.includes('/ko/')) {
                    detectedLang = 'ko';
                } else if (path.includes('-en/') || path.includes('/en/') || path.includes('simulator-en')) {
                    detectedLang = 'en';
                } else {
                    detectedLang = navigator.language.startsWith('ko') ? 'ko' : 'en';
                }
            }
            // Bind click events to language switcher with redirect support
            document.querySelectorAll('.lang-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    const selectedLang = btn.dataset.lang;
                    const path = window.location.pathname;
                    // If on the live post, redirect to the translated post page
                    if ((selectedLang === 'en') ? (path.includes('gear-ratio-calculator-simulator-3')) : false) {
                        window.location.href = 'https://myengnote.com/gear-ratio-calculator-simulator-en/';
                    } else if ((selectedLang === 'ko') ? (path.includes('gear-ratio-calculator-simulator-en')) : false) {
                        window.location.href = 'https://myengnote.com/ko/gear-ratio-calculator-simulator-3/';
                    } else {
                        // Fallback: translate on-the-fly
                        applyLanguage(selectedLang);
                    }
                });
            });
            // Initialize language setting on page load
            applyLanguage(detectedLang);
            // Canvas Resizing (Retina support)
            function resizeCanvas() {
                const rect = canvas.getBoundingClientRect();
                const dpr = window.devicePixelRatio || 1;
                canvas.width = rect.width * dpr;
                canvas.height = rect.height * dpr;
                ctx.scale(dpr, dpr);
            }
            resizeCanvas();
            window.addEventListener('resize', resizeCanvas);
            // Polling backup to guarantee resize
            setTimeout(resizeCanvas, 300);
            // Spark Particle System
            class GearSpark {
                constructor(x, y, vx, vy) {
                    this.x = x;
                    this.y = y;
                    this.vx = vx;
                    this.vy = vy;
                    this.size = Math.random() * 1.5 + 0.5;
                    this.life = Math.random() * 20 + 10;
                    this.maxLife = this.life;
                    const colors = ['#00f2fe', '#ff007f', '#ffffff'];
                    this.color = colors[Math.floor(Math.random() * colors.length)];
                }
                update() {
                    this.x += this.vx;
                    this.y += this.vy;
                    this.vy += 0.05; // soft gravity
                    this.life--;
                }
                draw(c) {
                    const alpha = this.life / this.maxLife;
                    c.save();
                    c.globalAlpha = alpha;
                    c.beginPath();
                    c.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                    c.fillStyle = this.color;
                    c.shadowBlur = 4;
                    c.shadowColor = this.color;
                    c.fill();
                    c.restore();
                }
            }
            // Sync Z1 Input and Slider
            function syncZ1FromSlider() {
                const val = parseInt(sliderZ1.value);
                inputZ1.value = val;
                state.z1 = val;
                clearPresets();
                updateCalculations();
            }
            function syncZ1FromInput() {
                let val = parseInt(inputZ1.value);
                if (isNaN(val) || val < 8) val = 8;
                if (val > 100) val = 100;
                sliderZ1.value = val;
                state.z1 = val;
                clearPresets();
                updateCalculations();
            }
            // Sync Z2 Input and Slider
            function syncZ2FromSlider() {
                const val = parseInt(sliderZ2.value);
                inputZ2.value = val;
                state.z2 = val;
                clearPresets();
                updateCalculations();
            }
            function syncZ2FromInput() {
                let val = parseInt(inputZ2.value);
                if (isNaN(val) || val < 8) val = 8;
                if (val > 100) val = 100;
                sliderZ2.value = val;
                state.z2 = val;
                clearPresets();
                updateCalculations();
            }
            // Sync RPM Input and Slider
            function syncRpmFromSlider() {
                const val = parseInt(sliderRpm.value);
                inputRpm.value = val;
                state.rpm = val;
                clearPresets();
                updateCalculations();
            }
            function syncRpmFromInput() {
                let val = parseInt(inputRpm.value);
                if (isNaN(val) || val < 0) val = 0;
                if (val > 3000) val = 3000;
                sliderRpm.value = val;
                state.rpm = val;
                clearPresets();
                updateCalculations();
            }
            // Sync Module
            function handleModuleChange() {
                let val = parseFloat(inputModule.value);
                if (isNaN(val) || val < 1.0) val = 1.0;
                if (val > 8.0) val = 8.0;
                state.m = val;
                updateCalculations();
            }
            // Core Math Calculations
            function updateCalculations() {
                const d1 = state.m * state.z1;
                const d2 = state.m * state.z2;
                const centerDist = (d1 + d2) / 2;
                const gearRatio = state.z2 / state.z1;
                const n2 = state.rpm / gearRatio;
                // Pitch Line Speed = omega * radius
                // PCD in mm, RPM -> linear velocity in m/s
                const r1_meters = (d1 / 2) / 1000;
                const omega1 = (2 * Math.PI * state.rpm) / 60;
                const pitchSpeed = omega1 * r1_meters;
                // Meshing frequency = frequency of gear teeth mesh
                const meshFreq = (state.rpm / 60) * state.z1;
                // Update UI Texts
                txtCenterDist.innerText = centerDist.toFixed(1) + ' mm';
                txtPitchSpeed.innerText = pitchSpeed.toFixed(2) + ' m/s';
                txtMeshFrequency.innerText = meshFreq.toFixed(1) + ' Hz';
                txtGearRatio.innerText = gearRatio.toFixed(2) + ' : 1';
                if (state.lang === 'ko') {
                    if (gearRatio > 1.0) {
                        txtRatioType.innerText = `${gearRatio.toFixed(2)}배 감속 (토크 ${gearRatio.toFixed(2)}배 증대)`;
                    } else if (gearRatio < 1.0) {
                        const gain = 1 / gearRatio;
                        txtRatioType.innerText = `${gain.toFixed(2)}배 증속 (토크 ${gearRatio.toFixed(2)}배 감소)`;
                    } else {
                        txtRatioType.innerText = '1:1 등속 동력 전달';
                    }
                    if (gearRatio === 1.0) {
                        txtTorqueMult.innerText = '100% (동일)';
                    } else {
                        txtTorqueMult.innerText = (gearRatio * 100).toFixed(0) + '%';
                    }
                } else {
                    if (gearRatio > 1.0) {
                        txtRatioType.innerText = `${gearRatio.toFixed(2)}x Reduction (Torque x${gearRatio.toFixed(2)})`;
                    } else if (gearRatio < 1.0) {
                        const gain = 1 / gearRatio;
                        txtRatioType.innerText = `${gain.toFixed(2)}x Increase (Torque x${gain.toFixed(2)})`;
                    } else {
                        txtRatioType.innerText = '1:1 Speed Matching';
                    }
                    if (gearRatio === 1.0) {
                        txtTorqueMult.innerText = '100% (Equal)';
                    } else {
                        txtTorqueMult.innerText = (gearRatio * 100).toFixed(0) + '%';
                    }
                }
                txtD1.innerText = d1.toFixed(1) + ' mm';
                txtD2.innerText = d2.toFixed(1) + ' mm';
                txtN2.innerText = n2.toFixed(1) + ' RPM';
            }
            // Preset Buttons Click Handler
            function loadPreset(key) {
                clearPresets();
                presetButtons.forEach(btn => {
                    if (btn.dataset.preset === key) {
                        btn.classList.add('active');
                    }
                });
                if (key === 'reduction') {
                    state.z1 = 12;
                    state.z2 = 48;
                    state.rpm = 200;
                    state.m = 2.5;
                } else if (key === 'mesh1to1') {
                    state.z1 = 24;
                    state.z2 = 24;
                    state.rpm = 150;
                    state.m = 3.0;
                } else if (key === 'increase') {
                    state.z1 = 36;
                    state.z2 = 12;
                    state.rpm = 100;
                    state.m = 3.0;
                }
                // Sync inputs
                inputZ1.value = state.z1;
                sliderZ1.value = state.z1;
                inputZ2.value = state.z2;
                sliderZ2.value = state.z2;
                inputRpm.value = state.rpm;
                sliderRpm.value = state.rpm;
                inputModule.value = state.m;
                updateCalculations();
            }
            function clearPresets() {
                presetButtons.forEach(btn => btn.classList.remove('active'));
            }
            // Draw Gear Teeth Path
            function drawGearOutline(c, teeth, pcd, mod, angleOffset) {
                const r_pitch = pcd / 2;
                const r_addendum = r_pitch + mod;
                const r_dedendum = r_pitch - 1.25 * mod;
                c.save();
                c.rotate(angleOffset);
                c.beginPath();
                for (let i = 0; i < teeth; i++) {
                    const stepAngle = (i * 2 * Math.PI) / teeth;
                    // Teeth geometry angles
                    const t0 = stepAngle - (2 * Math.PI / teeth) * 0.22;
                    const t1 = stepAngle - (2 * Math.PI / teeth) * 0.10;
                    const t2 = stepAngle + (2 * Math.PI / teeth) * 0.10;
                    const t3 = stepAngle + (2 * Math.PI / teeth) * 0.22;
                    const t4 = stepAngle + (2 * Math.PI / teeth) * 0.50; // valley mid point
                    const p0_x = Math.cos(t0) * r_dedendum;
                    const p0_y = Math.sin(t0) * r_dedendum;
                    const p1_x = Math.cos(t1) * r_addendum;
                    const p1_y = Math.sin(t1) * r_addendum;
                    const p2_x = Math.cos(t2) * r_addendum;
                    const p2_y = Math.sin(t2) * r_addendum;
                    const p3_x = Math.cos(t3) * r_dedendum;
                    const p3_y = Math.sin(t3) * r_dedendum;
                    const p4_x = Math.cos(t4) * r_dedendum;
                    const p4_y = Math.sin(t4) * r_dedendum;
                    if (i === 0) {
                        c.moveTo(p0_x, p0_y);
                    } else {
                        c.lineTo(p0_x, p0_y);
                    }
                    c.lineTo(p1_x, p1_y);
                    c.lineTo(p2_x, p2_y);
                    c.lineTo(p3_x, p3_y);
                    c.lineTo(p4_x, p4_y);
                }
                c.closePath();
                c.restore();
            }
            // Draw Gear Internals (Design details)
            function drawGearDetails(c, x, y, teeth, pcd, mod, angleOffset, themeColor) {
                const r_pitch = pcd / 2;
                c.save();
                c.translate(x, y);
                // 1. Draw outer teeth filled path
                drawGearOutline(c, teeth, pcd, mod, angleOffset);
                c.fillStyle = 'rgba(241, 245, 249, 0.85)';
                c.fill();
                c.strokeStyle = themeColor;
                c.lineWidth = 2.5;
                c.shadowBlur = 8;
                c.shadowColor = themeColor;
                c.stroke();
                c.shadowBlur = 0;
                // 2. Draw Pitch Circle (light dotted)
                c.beginPath();
                c.arc(0, 0, r_pitch, 0, Math.PI * 2);
                c.strokeStyle = 'rgba(15, 23, 42, 0.15)';
                c.lineWidth = 1;
                c.setLineDash([4, 4]);
                c.stroke();
                c.setLineDash([]);
                // 3. Draw internal cutouts and spokes
                c.save();
                c.rotate(angleOffset);
                // Shaft central hub
                c.beginPath();
                c.arc(0, 0, Math.max(r_pitch * 0.25, 12), 0, Math.PI * 2);
                c.strokeStyle = 'rgba(15, 23, 42, 0.25)';
                c.lineWidth = 2;
                c.stroke();
                c.beginPath();
                c.arc(0, 0, 5, 0, Math.PI * 2);
                c.fillStyle = '#ffffff';
                c.fill();
                // Spokes
                if (teeth >= 12) {
                    const spokes = teeth >= 30 ? 6 : 4;
                    for (let s = 0; s < spokes; s++) {
                        const spokeAngle = (s * 2 * Math.PI) / spokes;
                        c.save();
                        c.rotate(spokeAngle);
                        c.beginPath();
                        c.moveTo(0, Math.max(r_pitch * 0.25, 12));
                        c.lineTo(0, r_pitch - 10);
                        c.strokeStyle = 'rgba(15, 23, 42, 0.1)';
                        c.lineWidth = spokes === 6 ? 3 : 4;
                        c.stroke();
                        c.restore();
                    }
                }
                c.restore();
                // 4. Index marker (draw small dot on one tooth to visualize rotation easily)
                c.save();
                c.rotate(angleOffset);
                c.beginPath();
                c.arc(r_pitch - 6, 0, 3.5, 0, Math.PI * 2);
                c.fillStyle = '#ffffff';
                c.shadowBlur = 4;
                c.shadowColor = '#ffffff';
                c.fill();
                c.restore();
                c.restore();
            }
            function drawDiameterLeader(c, x, y, r, valStr, labelPrefix, side) {
                c.save();
                c.strokeStyle = 'rgba(71, 85, 105, 0.4)';
                c.lineWidth = 1.2;
                // Angle of leader line (45 degrees up-left or up-right)
                const angle = side === -1 ? -Math.PI * 0.75 : -Math.PI * 0.25;
                const px = x + Math.cos(angle) * r;
                const py = y + Math.sin(angle) * r;
                // Draw a beautiful small dot on the circle boundary
                c.beginPath();
                c.arc(px, py, 2.5, 0, Math.PI * 2);
                c.fillStyle = side === -1 ? '#0284c7' : '#db2777';
                c.fill();
                // Draw leader lines: from circle boundary diagonal outwards, then horizontal
                const lx1 = px + Math.cos(angle) * 20;
                const ly1 = py + Math.sin(angle) * 20;
                const lx2 = lx1 + side * 45;
                const ly2 = ly1;
                c.beginPath();
                c.moveTo(px, py);
                c.lineTo(lx1, ly1);
                c.lineTo(lx2, ly2);
                c.stroke();
                // Draw text above the horizontal line
                const text = `${labelPrefix} ${valStr}`;
                c.font = 'bold 10px var(--font-body)';
                const tx = side === -1 ? lx1 - 4 : lx1 + 4;
                c.fillStyle = '#1e293b';
                c.textAlign = side === -1 ? 'right' : 'left';
                c.textBaseline = 'bottom';
                c.fillText(text, tx, ly2 - 1);
                c.restore();
            }
            // Main Animation loop
            function animate(currentTime) {
                requestAnimationFrame(animate);
                let dt = (currentTime - state.lastTime) / 1000;
                if (isNaN(dt) || dt < 0 || dt > 1.0) dt = 0.016;
                state.lastTime = currentTime;
                const width = canvas.width / (window.devicePixelRatio || 1);
                const height = canvas.height / (window.devicePixelRatio || 1);
                const cx = width / 2;
                const cy = height / 2;
                ctx.clearRect(0, 0, width, height);
                // 1. Draw Grid
                ctx.save();
                ctx.strokeStyle = 'rgba(2, 132, 199, 0.06)';
                ctx.lineWidth = 1;
                for (let x = 0; x < width; x += 30) {
                    ctx.beginPath();
                    ctx.moveTo(x, 0);
                    ctx.lineTo(x, height);
                    ctx.stroke();
                }
                for (let y = 0; y < height; y += 30) {
                    ctx.beginPath();
                    ctx.moveTo(0, y);
                    ctx.lineTo(width, y);
                    ctx.stroke();
                }
                ctx.restore();
                // 2. Mesh physics calculations
                const d1 = state.m * state.z1;
                const d2 = state.m * state.z2;
                const r1 = d1 / 2;
                const r2 = d2 / 2;
                const centerDist = r1 + r2;
                // Scale visualization to fit screen dynamically
                // Mathematical bounding model to prevent any dimension label clipping on the left/right
                const totalWidthRequired = 1.707 * centerDist + 210;
                const totalHeightRequired = Math.max(d1, d2) + 120;
                const scale = Math.min(width / totalWidthRequired, height / totalHeightRequired);
                // Floating indicator scale update
                const txtCanvasScale = document.getElementById('txt-canvas-scale');
                if (txtCanvasScale) {
                    if (state.lang === 'ko') {
                        txtCanvasScale.innerText = `스케일 비율: 1:${(1/scale * 100).toFixed(0)}급`;
                    } else {
                        txtCanvasScale.innerText = `Scale: 1:${(1/scale * 100).toFixed(0)}`;
                    }
                }
                // Centering centers
                const x1 = cx - (centerDist / 2) * scale;
                const y1 = cy;
                const x2 = cx + (centerDist / 2) * scale;
                const y2 = cy;
                const gearRatio = state.z2 / state.z1;
                if (state.isPlaying) {
                    if (state.rpm > 0) {
                        const omega1 = (2 * Math.PI * state.rpm) / 60; // rad/s
                        // Apply stroboscopic limit for fast rotation rendering
                        const maxRenderOmega = 6;
                        const renderOmega1 = maxRenderOmega * (1 - Math.exp(-omega1 / maxRenderOmega));
                        state.angle1 += state.direction * renderOmega1 * dt;
                        state.angle2 = -state.angle1 / gearRatio;
                    }
                }
                // Mesh Point = exact touching tangent point of pitch circles
                const mesh_x = x1 + r1 * scale;
                const mesh_y = cy;
                // 3. Spawning meshing sparks at contact point
                if (state.isPlaying) {
                    if (state.rpm > 0) {
                        const sparkEmission = Math.min(Math.floor(state.rpm / 200) + 1, 3);
                        for (let s = 0; s < sparkEmission; s++) {
                            if (Math.random() > 0.4) {
                                const sparkVx = (Math.random() - 0.5) * 2;
                                const sparkVy = -Math.random() * (state.rpm / 150 + 1.5) - 0.5;
                                state.sparks.push(new GearSpark(mesh_x, mesh_y, sparkVx, sparkVy));
                            }
                        }
                    }
                }
                // Render Sparks
                state.sparks = state.sparks.filter(s => s.life > 0);
                state.sparks.forEach(s => {
                    s.update();
                    s.draw(ctx);
                });
                // 4. Draw Center Distance dimensions
                ctx.save();
                ctx.beginPath();
                ctx.moveTo(x1, y1);
                ctx.lineTo(x2, y2);
                ctx.strokeStyle = 'rgba(0, 0, 0, 0.05)';
                ctx.lineWidth = 1.5;
                ctx.setLineDash([4, 4]);
                ctx.stroke();
                ctx.restore();
                // Draw Gear 1 (Drive - Cyan)
                // Add a small initial tooth phase offset so meshing matches perfectly
                const phase1 = 0;
                drawGearDetails(ctx, x1, y1, state.z1, d1 * scale, state.m * scale, state.angle1 + phase1, '#0284c7');
                // Draw Gear 2 (Driven - Magenta)
                // For perfect tooth meshing: Gear 2 tooth needs to align to Gear 1 valley.
                // An angular phase shift of Math.PI / state.z2 aligns teeth perfectly.
                const phase2 = Math.PI + Math.PI / state.z2;
                drawGearDetails(ctx, x2, y2, state.z2, d2 * scale, state.m * scale, state.angle2 + phase2, '#db2777');
                // 5. Contact pitch point glow (small cyan glowing ring)
                ctx.save();
                ctx.beginPath();
                ctx.arc(mesh_x, mesh_y, 6, 0, Math.PI * 2);
                ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
                ctx.shadowBlur = 10;
                ctx.shadowColor = '#0284c7';
                ctx.fill();
                ctx.restore();
                // 6. Draw Diameter dimensions on gears with professional CAD leader lines
                drawDiameterLeader(ctx, x1, y1, r1 * scale, d1.toFixed(1) + ' mm', 'PCD₁ =', -1);
                drawDiameterLeader(ctx, x2, y2, r2 * scale, d2.toFixed(1) + ' mm', 'PCD₂ =', 1);
                // Horizontal Center Distance Dimension Line (C)
                ctx.save();
                ctx.strokeStyle = 'rgba(71, 85, 105, 0.3)';
                ctx.lineWidth = 1;
                const dimY = y1 + r2 * scale + 25; // 25px below larger gear
                ctx.beginPath();
                ctx.moveTo(x1, y1 + 10);
                ctx.lineTo(x1, dimY + 5);
                ctx.moveTo(x2, y2 + 10);
                ctx.lineTo(x2, dimY + 5);
                ctx.stroke();
                ctx.beginPath();
                ctx.moveTo(x1, dimY);
                ctx.lineTo(x2, dimY);
                ctx.stroke();
                function drawHorizontalArrowhead(px, py, direction) {
                    ctx.save();
                    ctx.translate(px, py);
                    ctx.fillStyle = 'rgba(71, 85, 105, 0.5)';
                    ctx.beginPath();
                    ctx.moveTo(0, 0);
                    ctx.lineTo(direction * 6, -3);
                    ctx.lineTo(direction * 6, 3);
                    ctx.closePath();
                    ctx.fill();
                    ctx.restore();
                }
                drawHorizontalArrowhead(x1, dimY, 1);
                drawHorizontalArrowhead(x2, dimY, -1);
                const cVal = (d1 + d2) / 2;
                const cText = `C = ${cVal.toFixed(1)} mm`;
                ctx.font = 'bold 9px Inter, sans-serif';
                const cTw = ctx.measureText(cText).width;
                ctx.fillStyle = '#ffffff';
                ctx.fillRect((x1 + x2)/2 - cTw/2 - 4, dimY - 5, cTw + 8, 10);
                ctx.fillStyle = '#475569';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.fillText(cText, (x1 + x2)/2, dimY);
                ctx.restore();
            }
            // Sync Controls
            sliderZ1.addEventListener('input', syncZ1FromSlider);
            inputZ1.addEventListener('change', syncZ1FromInput);
            sliderZ2.addEventListener('input', syncZ2FromSlider);
            inputZ2.addEventListener('change', syncZ2FromInput);
            sliderRpm.addEventListener('input', syncRpmFromSlider);
            inputRpm.addEventListener('change', syncRpmFromInput);
            inputModule.addEventListener('change', handleModuleChange);
            btnPlayPause.addEventListener('click', () => {
                state.isPlaying = !state.isPlaying;
                const labelText = state.isPlaying
                    ? (state.lang === 'ko' ? '일시정지' : 'Pause')
                    : (state.lang === 'ko' ? '재생' : 'Play');
                const iconClass = state.isPlaying ? 'fa-pause' : 'fa-play';
                btnPlayPause.innerHTML = `<i class="fa-solid ${iconClass}"></i> <span>${labelText}</span>`;
            });
            btnReverse.addEventListener('click', () => {
                state.direction *= -1;
            });
            presetButtons.forEach(btn => {
                btn.addEventListener('click', () => {
                    loadPreset(btn.dataset.preset);
                });
            });
            // Initialize calculations and presets
            loadPreset('reduction');
            requestAnimationFrame(animate);
            // ── 우클릭 & 소스 복사 방지 (전체 문서 레벨 + 알림창 동기화) ──
            document.addEventListener('contextmenu', function(e) {
                e.preventDefault();
                const msg = state.lang === 'ko' 
                    ? "이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다."
                    : "This content is protected by copyright law. Copying and right-clicking are prohibited.";
                alert(msg);
                return false;
            }, { capture: true });
            document.addEventListener('selectstart', function(e) {
                e.preventDefault();
                return false;
            }, { capture: true });
            // 개발자도구 단축키 및 복사 단축키 차단 (F12, Ctrl+U, Ctrl+Shift+I/J/C, Ctrl+C, Ctrl+S)
            document.addEventListener('keydown', function(e) {
                const msg = state.lang === 'ko' 
                    ? "이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다."
                    : "This content is protected by copyright law. Copying and right-clicking are prohibited.";
                if (e.key === 'F12') {
                    e.preventDefault();
                    alert(msg);
                    return false;
                }
                if (e.ctrlKey) {
                    if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
                        e.preventDefault();
                        alert(msg);
                        return false;
                    }
                    if (e.shiftKey) {
                        if (['i','I','j','J','c','C'].includes(e.key)) {
                            e.preventDefault();
                            alert(msg);
                            return false;
                        }
                    }
                }
            }, { capture: true });
        } // <-- Closed the initGearSimulator function
        // Robust ReadyState hook-up with polling to guarantee execution even if DOM elements load late
        let initAttempts = 0;
        function tryInit() {
            initAttempts++;
            initGearSimulator();
            if (!window.__gearratio_initialized) {
                if (initAttempts < 50) {
                    setTimeout(tryInit, 100);
                }
            }
        }
        if (document.readyState === 'complete' || document.readyState === 'interactive') {
            tryInit();
        } else {
            document.addEventListener('DOMContentLoaded', tryInit);
            window.addEventListener('load', tryInit);
        }
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>기어 잇수 조절: 슬라이더나 입력 칸을 통해 구동 기어(Gear 1)와 피동 기어(Gear 2)의 잇수(Z)를 설정합니다.</strong></li>
<li style="margin-bottom: 6px;">입력 회전수(RPM) 및 모듈 조절: 구동 기어의 RPM과 기어의 모듈(m) 값을 입력하여 속도와 물리적 크기를 정합니다.</li>
<li style="margin-bottom: 6px;">실시간 기어 맞물림 관찰: 설정에 따라 두 기어가 완벽히 맞물려 회전하는 물리 애니메이션과 접촉면의 실시간 파티클 스파크를 관찰합니다.</li>
<li style="margin-bottom: 6px;">출력 데이터 분석: 기어비, 피치원 지름(PCD), 중심거리, 출력 RPM 및 토크 배율 변화를 실시간 계측 모니터로 정밀 분석합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 상세 기계공학 해설 및 기어 설계 규격 (KS/ISO) 확인하기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 기어비(Gear Ratio)의 기본 개념 및 기계설계적 의의</h3>
<p>기어비(Gear Ratio, <code>i</code>)는 두 개의 맞물린 기어 사이에서 입력축과 출력축의 회전수 비율 및 토크 변화율을 결정하는 핵심 설계 인자입니다. 동력전달장치 설계에서 기어비는 모터의 회전 속도를 기계 작동에 적합한 속도로 감속시키거나(감속기), 필요한 작동 토크를 증대시키기 위해 정밀하게 조정됩니다.</p><ul><li><strong>속도비 (Speed Ratio):</strong> 기어비가 1보다 크면 출력 속도는 줄어들며, 감속비가 형성됩니다. 반대로 1보다 작으면 증속이 일어납니다.</li><li><strong>토크 변환 (Torque Multiplier):</strong> 에너지 보존 법칙(동력 일정)에 의해 감속 비율에 비례하여 출력 토크가 증가합니다.</li><li><strong>역학적 효율성:</strong> 기어의 형상(이의 치형)에 따라 동력 전달 효율이 달라지며, KS B ISO 규격에 따른 치형 관리가 중요합니다.</li></ul>
<h3>2. 기어 치수 및 역학 공식 관계식 유도</h3>
<p>기어의 기하학적 형상과 맞물림 동역학을 계산하는 공식들은 다음과 같이 유도됩니다.</p><p><strong>① 피치원 지름 (Pitch Circle Diameter, PCD):</strong> 기어가 만나는 가상의 마찰원 지름으로, 모듈(<code>m</code>)과 잇수(<code>Z</code>)의 곱으로 구합니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">d = m &times; Z &nbsp;[mm]</p><p><strong>② 기어비 (Gear Ratio, i) 및 출력 속도 (N2):</strong> 구동기어 잇수를 <code>Z1</code>, 피동기어 잇수를 <code>Z2</code>라 할 때, 맞물림 선속도가 일정하므로 잇수 비율에 역비례하여 회전수가 결정됩니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">i = Z2 / Z1 = N1 / N2</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.05em; color: #0369a1;">N2 = N1 &times; (Z1 / Z2) &nbsp;[RPM]</p><p><strong>③ 축간 중심거리 (Center Distance, a):</strong> 두 기어의 피치원이 외접할 때의 회전축 간 거리입니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">a = (d1 + d2) / 2 = m &times; (Z1 + Z2) / 2 &nbsp;[mm]</p>
<h3>3. 전동 효율 및 기어 파손 설계 (루이스 공식)</h3>
<p>기어설계 시 단순히 치수만 맞추는 것이 아니라, 전달할 동력에 따른 이뿌리 굽힘 강도(Bending Strength)와 이면 접촉 응력(Surface Durability)을 검토해야 합니다. 전통적인 굽힘 강도 계산에는 다음과 같은 <strong>루이스 공식(Lewis Formula)</strong>이 기초가 됩니다.</p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">&sigma;_b = F_t / (b &times; m &times; Y)</p><p>여기서 <code>F_t</code>는 전달 접선력(N), <code>b</code>는 치폭(mm), <code>m</code>은 모듈, <code>Y</code>는 이의 형상에 따른 루이스 치형 계수(Form Factor)입니다. 현대 기계설계 규격(KS B ISO 6336 등)은 이 Lewis 공식을 한 단계 발전시켜 하중분포 계수, 동하중 계수, 속도 계수 등을 종합적으로 반영하여 피로 파손 한계를 평가합니다.</p>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/gear-ratio-calculator-simulator-3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>표준 부품 라이브러리의 경제성 (Economic Value of Standard Parts Library)</title>
		<link>https://myengnote.com/economic-value-of-standard-parts-library/</link>
					<comments>https://myengnote.com/economic-value-of-standard-parts-library/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Thu, 21 May 2026 16:37:17 +0000</pubDate>
				<category><![CDATA[KS규격/기계요소]]></category>
		<category><![CDATA[CAD]]></category>
		<category><![CDATA[MechanicalDesign]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[원가절감]]></category>
		<category><![CDATA[캐드라이브러리]]></category>
		<category><![CDATA[표준부품]]></category>
		<guid isPermaLink="false">https://myengnote.com/economic-value-of-standard-parts-library/</guid>

					<description><![CDATA[기계 설계 단계에서 표준 부품 라이브러리를 도입하는 것이 단순한 시간 단축을 넘어 기업의 총 소유 비용과 직결되는 경제적 이유를 실무 관점에서 심도 있게 분석합니다.... <a href="https://myengnote.com/economic-value-of-standard-parts-library/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[<p>내구성을 고려한 설계를 진행할 때, 표준 부품 라이브러리 활용은 단순한 기성 부품의 짜깁기가 아닙니다. 이는 기계 장비의 기하학적 정밀도와 구조적 반복 능력을 물리적으로 보장하는 강력한 설계적 안전장치입니다. 수많은 엔지니어들이 독창적인 장비를 만든다는 목적 하에 기성품을 모방하여 자체 가공품을 도면화하곤 하지만, 이는 재료 역학적 관점과 가공 공차 제어 측면에서 매우 위험한 도박이 될 수 있습니다. 기계 설계를 진행할 때 기성 표준 부품 라이브러리를 선제적으로 구축하고 이를 철저하게 준수하는 것은, 비선형적으로 증가하는 엔지니어링 리소스와 생산 원가를 제어하기 위한 필수적인 설계 철학입니다.</p>
<h2>설계 철학과 시간의 함수</h2>
<p>설계 초기 단계에서 캐드 라이브러리를 열어 규격품을 배치하는 행위는 단순히 3차원 형상을 화면에 얹는 것 이상의 가치를 가집니다. 맞춤형 가공 부품을 새로 설계하기 위해서는 형상 정의, 치수 공차 지정, 표면 거칠기 결정, 그리고 열처리와 도금 사양 정의까지 수많은 변수를 인간이 직접 결정해야 합니다. 이 과정에서 설계자의 피로도에 따라 설계 오류가 발생할 확률은 기하급수적으로 증가하게 됩니다. 특히 부품의 기능적 인터페이스가 복잡해질수록 이러한 수동 제어 방식은 한계에 봉착합니다.</p>
<p>반면, 표준 부품 라이브러리는 이미 국제 표준인 ISO나 국가 표준인 KS 규격에 따라 모든 기하학적 변수와 응력 분포가 철저히 검증되어 있습니다. 예를 들어 볼트 체결부나 베어링 장착부의 치수 설계를 직접 계산하여 매번 도면화하는 것과, 정립된 규격 라이브러리를 불러와 설계하는 것은 장비 품질 관리 차원에서 엄청난 정밀도 차이를 보입니다. 비표준 부품의 남발은 가공 현장에서의 장비 설정 시간을 늘리고, 불필요한 전용 지그와 고정구 설계를 추가로 요구하게 되어 전반적인 제조 원가를 상승시키는 주범이 됩니다.</p>
<div style="border-left: 5px solid #3b82f6; background-color: #eff6ff; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"><span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d8.png" alt="📘" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="font-weight: bold; color: #1e40af; font-size: 1.2em;">핵심 요약</span></div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">표준 부품 라이브러리를 사용하는 것은 물리적 성질과 한계 하중이 완벽히 검증된 가상의 부품을 조립하는 과정입니다. 이는 조립 현장의 불확실성을 완전히 소거하고 장비의 유동적인 유지보수를 보장하는 경제적 가치 사슬의 출발점입니다.</div>
</p>
</div>
<h2>가공 오차와 재료 역학</h2>
<p>비표준 가공품의 가장 큰 아킬레스건은 열처리와 하중 집중에 따른 피로 한계 예측이 불가능하다는 점입니다. 기계 장비가 구동하면서 발생하는 지속적인 비틀림 응력이나 고주파 진동 하에서, 임의 설계로 깎아 만든 특수 축이나 칼라는 예측하지 못한 부위에서 피로 파괴를 겪기 쉽습니다. 특히 기계 축의 응력 집중 지점에 적절한 라운드 처리가 누적되지 않거나 공차가 무너지면, 모터의 토크가 전달될 때 국부적인 전단 응력이 발생하여 영구 변형을 초래합니다.</p>
<p>표준 기성 부품, 가령 탄소강이나 합금강 계열의 규격 샤프트 홀더, 칼라, 리니어 가이드 브래킷 등은 균일한 가열 경화 처리가 적용되어 표면 경도가 일정하게 유지됩니다. 덕분에 마찰로 인한 금속 재료 표면의 융착 현상인 골링(Galling) 현상을 물리적으로 방지할 수 있습니다. 자체 임의 가공 설계를 통해 이 정도 수준의 재료적 신뢰성을 확보하려면, 시제품 제작 비용이 규격품 구매 비용의 수십 배를 넘어서게 됩니다. 소량 다품종 생산 위주의 정밀 자동화 시스템 산업에서 표준 부품 라이브러리 없이 매번 도면을 새로 그리는 것은 회사의 개발 예산을 낭비하는 일과 다름없습니다.</p>
<h2>실무 필드 로그 및 분석 (Field Log &#038; Analysis)</h2>
<ul>
<li><strong>설비 정보</strong>: 반도체 정밀 웨이퍼 이송 모듈 (모델명: Smart-Transformer MX-200)</li>
<li><strong>적용 컴포넌트</strong>: SMC 공압 액추에이터, SKF 복열 앵귤러 콘택트 베어링, Mitsubishi 서보 구동 시스템</li>
<li><strong>현장 이상 징후</strong>: 주 회전 축 모듈 구동 시 180Hz 영역에서 날카로운 고주파 이상 진동이 연속적으로 발생하였으며, 물리적으로 축 방향 1.2mm의 비정상적인 축 방향 유격(Axial Play)이 측정됨.</li>
<li><strong>물리적 원인 규명</strong>: 정밀 다이얼 게이지 및 분해 분석 결과, 가혹 구동 환경 하에서 발생한 반복 모멘트 하중으로 인해 비표준으로 자체 설계 및 일반 흑색산화피막 가공되었던 특수 샤프트 엔드 칼라의 나사산 부근에서 기계적 피로로 인한 변형 및 미세 균열이 확인되었습니다. 이는 KS B ISO 286(선형 치수의 공차 시스템) 및 KS B 2002(구름 베어링-고정용 부품)에 준하는 정밀한 끼워맞춤 공차가 도면에 반영되지 못해 조립부 헐거워짐이 발생한 것이 근본 원인이었습니다.</li>
<li><strong>비즈니스 임팩트 분석</strong>: 해당 라인의 설비 정지 시간 피해액은 시간당 약 4,500만 원으로 산출되었습니다. 비표준 임의 가공품을 다시 제어하여 재가공하고 도금 및 검수 과정을 거쳐 현장에 조달하는 데는 최소 5일의 리드타임이 필요했습니다. 반면, 현장에서 규격 사양의 기성 샤프트 칼라와 베어링 로크너트 표준 라이브러리를 활용해 설계 변경 후 즉시 대체품을 수급함으로써 부품 자재비를 94% 절감하고, 단 2시간 만에 장비를 정상 복구하여 수억 원의 잠재적 생산 손실을 방지했습니다.</li>
</ul>
<div style="border-left: 5px solid #f59e0b; background-color: #fffbeb; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"><span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="font-weight: bold; color: #92400e; font-size: 1.2em;">현장 전문가의 팁</span></div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">장비 사후 관리 도면을 제작할 때, 비표준 가공품의 형상을 일일이 그려 넣는 것보다 신뢰성 있는 부품 제조사의 파트 넘버를 품명에 직접 기입하는 것을 원칙으로 삼으십시오. 이를 통해 전 세계 어디서나 동일한 기하학적 치수와 경도를 지닌 표준 부품을 즉각 조달받을 수 있는 정비 체계가 완성됩니다.</div>
</p>
</div>
<h2>초보 엔지니어들이 흔히 하는 실수</h2>
<p>주니어 엔지니어들은 종종 본인만의 독특하고 최적화된 기계 구조를 만들겠다는 욕심 때문에 모든 요소 부품을 일일이 새로 도면화하는 치명적인 실수를 범합니다. 대표적인 사례가 나사의 피치, 깊이, 또는 카운터보어나 카운터싱크의 각도를 규격 외로 정의하여 가공을 의뢰하는 행위입니다. 표준 라이브러리를 무시한 이러한 고집은 단품 가공 비용의 폭발적 증가를 야기할 뿐 아니라, 가공품의 공차 조율 실패로 인해 조립 정밀도를 무너뜨리는 결과를 낳습니다.</p>
<p>조립 현장에서의 작업 편의성을 배려하지 못해 생기는 문제도 빈번합니다. 표준화된 지그와 고정구 라이브러리를 쓰지 않고 맞춤형 고정용 블록을 전부 가공 제작하면 가공 편차가 심해져 작업 품질 균일화가 불가능해집니다. 또한 표준 스프링 핀이나 다웰 핀의 홀 직경에 대한 끼워맞춤 공차 적용을 가볍게 여겨, 압입 공정 중 부품이 전단되거나 균열이 가며 제품 전체를 폐기해야 하는 금전적 손실이 흔하게 나타납니다.</p>
<div style="border-left: 5px solid #ef4444; background-color: #fef2f2; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"><span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="font-weight: bold; color: #991b1b; font-size: 1.2em;">주의사항</span></div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">메이커가 제공하는 캐드 데이터 라이브러리를 그대로 다운로드하여 배치할 때는, 해당 데이터의 가상 형상과 실물 부품의 실제 오차 범위를 반드시 사전에 대조하여 검증해야 합니다. 간혹 치수 공차가 누적되는 극단적 한계 조건에서 간섭이 발생하는 경우가 발생할 수 있습니다.</div>
</p>
</div>
<h2>설계 책임자의 최종 권고</h2>
<p>기계 구조의 원가 개선과 유지보수 효율 향상을 진두지휘하는 책임자 관점에서 제언하자면, 장비 전체 도면에 포함되는 비표준 가공 부품의 비중을 전체의 25% 미만으로 통제하는 엄격한 설계 검토 프로세스를 도입해야 합니다. 규격 라이브러리를 활용해 표준화율을 극대화하는 설계는 제조 공정의 간소화뿐 아니라 부품 공급망 안정화로 직결됩니다. 기성 부품을 최대한 활용해 가혹하고 특수한 조건에서 설계 안정성을 다지는 것만이 기업의 사후 보증 비용을 아끼고 품질 평판을 견고히 다지는 정석입니다.</p>
<h2>0. 연관글</h2>
<p> <!-- START_SIMULATOR_LINK_CARD_stress_strain --><a href="https://myengnote.com/stress-strain-relation-calculator-simulator/" target="_blank" rel="noopener noreferrer" class="eng-simulator-card" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ee.png" alt="🧮" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #10b981; font-weight: bold; margin-bottom: 4px;">실시간 공학 시뮬레이터 추천</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">재료역학 응력-변형률(Hooke 법칙) 계산기 &#038; 실시간 인장 시뮬레이터</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #10b981; font-size: 24px; font-weight: bold;">→</span></a><!-- END_SIMULATOR_LINK_CARD_stress_strain --><a href="https://myengnote.com/basics-of-power-transmission-mechanical-shaft-material-selection/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">기계 축의 역할과 재질 선정의 중요성 (Basics of Power Transmission: Role of Mechanical Shafts and Material Selection)</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span></a><a href="https://myengnote.com/machining-differences-round-vs-countersunk-screws/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">둥근머리 및 접시머리 나사 가공 설계 차이</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span></a><a href="https://myengnote.com/definition-and-benefits-of-jigs-and-fixtures/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">지그와 고정구의 정의 및 현장 도입 효과</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span></a></p>
<hr style="border: 0; border-top: 1px solid #eee; margin: 40px 0 20px 0;">
<p style="text-align: center; font-size: 0.85em; color: #888; margin-bottom: 20px;">
    본 콘텐츠는 저작권법의 보호를 받으며, 무단 전재 및 재배포를 금지합니다.<br />
    Copyright 2026. 동동 All rights reserved.
</p>
<p><!-- Protection Scripts --></p>
<div id="protection-script" style="display:none;">
<script>
document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
    alert('이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.');
});
document.addEventListener('keydown', function(e) {
    if (e.ctrlKey && (e.key === 'c' || e.key === 'u' || e.key === 'a')) {
        e.preventDefault();
        alert('무단 복제를 금지합니다.');
    }
});
</script></p>
<style>
.entry-content {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
</style>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/economic-value-of-standard-parts-library/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>기어비 계산법: 속도와 토크의 반비례 관계 (Gear Ratio Calculation: Understanding Speed and Torque)</title>
		<link>https://myengnote.com/gear-ratio-calculation-speed-torque-relationship/</link>
					<comments>https://myengnote.com/gear-ratio-calculation-speed-torque-relationship/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Tue, 12 May 2026 21:18:08 +0000</pubDate>
				<category><![CDATA[동력전달장치/구동부]]></category>
		<category><![CDATA[Gear Ratio]]></category>
		<category><![CDATA[Speed]]></category>
		<category><![CDATA[Torque]]></category>
		<category><![CDATA[감속기]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[기어비]]></category>
		<category><![CDATA[동력전달]]></category>
		<category><![CDATA[토크계산]]></category>
		<guid isPermaLink="false">https://myengnote.com/gear-ratio-calculation-speed-torque-relationship/</guid>

					<description><![CDATA[기어비의 기본 원리와 속도 및 토크 간의 반비례 관계를 심층 분석합니다. 실무 현장의 감속기 설계 사례와 에너지 보존 법칙에 근거한 정확한 계산법을 가이드합니다.... <a href="https://myengnote.com/gear-ratio-calculation-speed-torque-relationship/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[<p>내구성을 고려한 기계 설계에 있어 기어비는 단순한 부품의 조합 그 이상의 의미를 갖습니다. 이는 시스템의 생명력을 결정짓는 핵심적인 안전장치이자, 제한된 동력을 가장 효율적으로 배분하는 설계자의 철학이 담긴 지표라고 할 수 있습니다. 우리가 흔히 접하는 감속기나 변속기 내부에서 일어나는 속도와 토크의 변화는 물리적 에너지 보존 법칙을 충실히 따르는 과정이며, 이를 정확히 이해하지 못한 설계는 결국 장비의 수명 단축이나 치명적인 파손으로 이어지기 마련입니다. 기어비의 본질을 이해하려면 먼저 입력단과 출력단 사이의 물리적 상호작용을 들여다봐야 합니다. 구동 기어(피니언)와 피동 기어 사이에서 발생하는 회전수의 차이는 곧 힘의 증폭 혹은 감쇄로 나타납니다. 여기서 중요한 점은 &#8216;일&#8217;의 개념입니다. 마찰 손실을 제외한다면 입력된 에너지는 출력단으로 그대로 전달되어야 하기에, 회전 속도가 줄어드는 만큼 그 보상으로 회전하는 힘, 즉 토크가 강해지는 것입니다. 이러한 반비례 관계는 기계 설계의 가장 기초적이면서도 강력한 원칙입니다. </p>
<div style="border-left: 5px solid #3b82f6; background-color: #eff6ff; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"><span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d8.png" alt="📘" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="font-weight: bold; color: #1e40af; font-size: 1.2em;">핵심 요약</span></div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">기어비(i)는 &#8216;피동 기어 잇수 / 구동 기어 잇수&#8217;로 계산됩니다. 출력 토크는 입력 토크에 기어비를 곱하고 효율을 반영하여 구하며, 출력 회전수는 입력 회전수를 기어비로 나누어 계산합니다. 즉, 기어비가 커질수록 속도는 느려지지만 힘은 강력해집니다.</div>
</p>
</div>
<h2>실무 필드 로그 및 분석 (Field Log &#038; Analysis)</h2>
<p> <strong>[현장 상황 리포트]</strong><br />
최근 국내의 한 자동차 부품 조립 라인에서 대형 컨베이어 구동부가 빈번하게 멈추는 현상이 발생했습니다. 해당 설비에는 Mitsubishi 사의 HG-SR 시리즈 서보 모터와 Sumitomo 사의 파라맥스 감속기가 조합되어 운용 중이었습니다. 현장에서 측정된 감속기 하우징의 표면 온도는 약 95°C에 달했으며, 180Hz 부근에서 고주파 진동이 관찰되었습니다. <strong>[분석 및 진단]</strong><br />
초기 설계 당시 예상했던 부하보다 실제 운전 부하가 약 1.5배 높게 측정되었습니다. 기존에 적용된 15:1의 기어비로는 가속 구간에서 모터에 가해지는 관성 부하를 충분히 제어하지 못해 모터가 지속적인 과부하 상태에 놓여 있었습니다. 이로 인해 슬립 현상이 가속화되고 내부 오일 온도가 급상승하며 베어링의 점성 마찰이 커지는 악순환이 반복되고 있었습니다. <strong>[조치 결과 및 경제적 효과]</strong><br />
설계 변경을 통해 기어비를 25:1로 상향 조정하고, 이에 맞춰 모터의 제어 파라미터를 재설정했습니다. 비록 컨베이어의 최대 이동 속도는 약간 줄어들었으나, 출력 토크가 약 66% 증폭되면서 모터의 정격 전류 범위 내에서 안정적인 가동이 가능해졌습니다. 이 조치를 통해 월평균 3회 발생하던 예기치 못한 정지 시간을 제로화하였으며, 연간 약 4,500만 원 상당의 생산 손실을 방지하는 효과를 가져왔습니다. 해당 설계는 <strong>KS B ISO 6336</strong>(평기어 및 헬리컬 기어의 부하 용량 계산) 규격을 준수하여 강도 계산을 재검증하였습니다. </p>
<h2>속도와 토크의 물리적 줄다리기</h2>
<p>엔지니어로서 설계를 진행할 때 가장 먼저 맞닥뜨리는 고민은 &#8220;얼마나 빠른 모터를 쓸 것인가&#8221;가 아니라 &#8220;얼마나 큰 힘이 필요한가&#8221;입니다. 기어비는 이 질문에 대한 해답을 주는 가변 상수와 같습니다. 모터의 출력은 고정되어 있는데, 이를 빠른 속도로 쓸 것인지, 아니면 느리지만 묵직한 힘으로 쓸 것인지를 결정하는 도구가 바로 기어입니다.</p>
<p> 기어비 계산의 기본 공식은 매우 명쾌합니다. 기어비(i)는 피동 기어의 잇수를 구동 기어의 잇수로 나눈 값입니다. 예를 들어 모터 축에 달린 10개의 이를 가진 기어가 50개의 이를 가진 큰 기어를 돌린다면 기어비는 5가 됩니다. 이때 출력 축의 속도는 모터 속도의 1/5로 줄어들지만, 이론적인 토크는 5배로 커집니다. 하지만 여기서 간과해서는 안 될 점이 바로 효율입니다. 기어 치면 사이의 마찰, 오일의 점성 저항 등으로 인해 실제 전달되는 토크는 계산값의 90~95% 수준에 머무는 경우가 많습니다. </p>
<div style="border-left: 5px solid #ef4444; background-color: #fef2f2; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"><span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="font-weight: bold; color: #991b1b; font-size: 1.2em;">주의사항</span></div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">고감속비(예: 100:1 이상)를 설계할 때는 반드시 열적 정격을 확인해야 합니다. 토크는 충분하더라도 내부 마찰로 인한 발열량이 발산량보다 많으면 기어가 소각될 위험이 있습니다. 특히 웜 기어의 경우 효율이 급격히 떨어지므로 방열 대책이 필수적입니다.</div>
</p>
</div>
<h2>현장에서 놓치기 쉬운 계산의 함정들</h2>
<p>많은 초보 엔지니어들이 기어비만 맞추면 모든 것이 해결될 것이라 믿곤 합니다. 하지만 실무에서는 &#8216;관성 모멘트의 정합&#8217;이라는 더 높은 벽이 존재합니다. 모터가 기어 박스를 통해 부하를 돌릴 때, 부하의 관성은 기어비의 제곱에 반비례하여 모터 측에 전달됩니다.</p>
<p> 즉, 기어비를 높이면 모터가 느끼는 부하의 무게감이 기하급수적으로 가벼워진다는 뜻입니다. 이는 제어의 안정성을 확보하는 데 매우 유리한 조건이 됩니다. 또한, 다단 감속기를 설계할 때는 각 단계별 기어비의 곱이 최종 기어비가 된다는 점을 명심해야 합니다. 1단에서 3:1, 2단에서 4:1로 감속한다면 최종 기어비는 12:1이 됩니다. 이때 각 단계의 샤프트와 베어링이 견뎌야 하는 하중은 뒤로 갈수록 커지므로, 출력단에 가까운 부품일수록 더 굵은 축과 강한 소재를 사용해야 합니다. 만약 이를 무시하고 동일한 규격의 부품을 사용한다면, 출력단 샤프트가 토크를 이기지 못하고 비틀려 부러지는 사고가 발생할 수 있습니다. </p>
<div style="overflow-x: auto; white-space: nowrap; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); margin: 20px 0; border: 1px solid #e5e7eb;">
<table style="border-collapse: collapse; width: 100%; min-width: 700px; font-size: 15px; text-align: left; background-color: #ffffff;">
<thead>
<tr style="background-color: #1f2937; color: #ffffff;">
<th style="padding: 15px; border-bottom: 3px solid #3b82f6; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em;">항목</th>
<th style="padding: 15px; border-bottom: 3px solid #10b981; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em;">입력단 (모터)</th>
<th style="padding: 15px; border-bottom: 3px solid #f59e0b; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em;">출력단 (기어비 10:1)</th>
<th style="padding: 15px; border-bottom: 3px solid #8b5cf6; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em;">물리적 변화</th>
</tr>
</thead>
<tbody>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">회전 속도 (RPM)</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">3000</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">300</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">1/10로 감소</td>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">회전 토크 (N·m)</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">5</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">45~48 (효율 반영)</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">약 10배 증가</td>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">관성 부하 (kg·m²)</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">부하 관성 / 100</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">실제 부하 관성</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">1/100로 감소</td>
</tr>
</tbody>
</table>
</div>
<h2>설계자의 관점에서 본 기어비의 가치</h2>
<p>기어비를 결정하는 과정은 단순히 수학 문제를 푸는 것이 아니라, 장비의 운명과 유지보수 비용을 설계하는 과정입니다. 너무 낮은 기어비는 모터의 빈번한 소각을 초래하고, 너무 높은 기어비는 불필요한 비용 상승과 기계적 효율 저하를 야기합니다.</p>
<p> 저는 후배 엔지니어들에게 항상 &#8220;카탈로그의 수치 뒤에 숨겨진 물리적 여유를 보라&#8221;고 조언합니다. 장비가 구동될 때 발생하는 이상 소음이나 진동은 기어비 설계가 잘못되었다는 가장 정직한 신호입니다. 예를 들어, 모터가 정격 속도보다 너무 낮은 구간에서 계속 운전된다면 냉각 팬의 효율이 떨어져 모터 수명이 급감하게 됩니다. 이러한 경우 차라리 기어비를 높여 모터가 제 성능을 낼 수 있는 고회전 영역에서 운전하게 하고, 대신 출력단의 힘을 보강하는 것이 장기적인 관점에서 훨씬 경제적입니다. </p>
<div style="border-left: 5px solid #f59e0b; background-color: #fffbeb; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"><span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="font-weight: bold; color: #92400e; font-size: 1.2em;">현장 전문가의 팁</span></div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">기어비를 선정할 때는 &#8216;소수점 기어비&#8217;를 고려해 보세요. 정수비(예: 4:1, 5:1)보다는 약간의 소수점이 섞인 비율(예: 4.12:1)이 기어 치면의 마모를 분산시켜 수명을 연장하는 데 도움이 됩니다. 이는 특정 이빨끼리만 반복해서 맞물리는 현상을 방지해 주기 때문입니다.</div>
</p>
</div>
<p> 결론적으로 기어비는 속도와 토크라는 두 마리 토끼를 잡기 위한 설계자의 전략적 선택지입니다. 에너지는 공짜로 얻어지지 않으며, 우리가 얻는 강력한 토크는 결국 속도의 희생이라는 대가를 치른 결과물입니다. 이 명확한 인과관계를 이해하고 실무에 적용한다면, 더욱 견고하고 신뢰성 높은 기계 시스템을 구축할 수 있을 것입니다. <a href="https://myengnote.com/understanding-ac-dc-motor-power-supply-control-characteristics/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">AC 및 DC 모터의 전원 방식과 제어 특성 이해</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span></a><a href="https://myengnote.com/worm-gear-reduction-principles-and-self-locking/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">웜 기어 감속 원리와 역전 방지 기능</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span></a> </p>
<h2>0. 연관글</h2>
<p><!-- START_SIMULATOR_LINK_CARD_gear_ratio --><a href="https://myengnote.com/gear-ratio-calculator-simulator-3/" target="_blank" rel="noopener noreferrer" class="eng-simulator-card" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ee.png" alt="🧮" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #10b981; font-weight: bold; margin-bottom: 4px;">실시간 공학 시뮬레이터 추천</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">초정밀 기어비 계산기 &#038; 실시간 2D 회전 시뮬레이터</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #10b981; font-size: 24px; font-weight: bold;">→</span></a><!-- END_SIMULATOR_LINK_CARD_gear_ratio --><a href="https://myengnote.com/risks-ignoring-abnormal-machine-noise/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">기계 이상 소음 방치의 위험성</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span></a></p>
<hr style="border: 0; border-top: 1px solid #eee; margin: 40px 0 20px 0;">
<p style="text-align: center; font-size: 0.85em; color: #888; margin-bottom: 20px;">
    본 콘텐츠는 저작권법의 보호를 받으며, 무단 전재 및 재배포를 금지합니다.<br />
    Copyright 2026. 동동 All rights reserved.
</p>
<p><!-- Protection Scripts --></p>
<div id="protection-script" style="display:none;">
<script>
document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
    alert('이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.');
});
document.addEventListener('keydown', function(e) {
    if (e.ctrlKey && (e.key === 'c' || e.key === 'u' || e.key === 'a')) {
        e.preventDefault();
        alert('무단 복제를 금지합니다.');
    }
});
</script></p>
<style>
.entry-content {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
</style>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/gear-ratio-calculation-speed-torque-relationship/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>둥근머리 및 접시머리 나사 가공 설계 차이 (Design and Machining Differences of Round and Countersunk Screws)</title>
		<link>https://myengnote.com/machining-differences-round-vs-countersunk-screws/</link>
					<comments>https://myengnote.com/machining-differences-round-vs-countersunk-screws/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Fri, 08 May 2026 21:56:10 +0000</pubDate>
				<category><![CDATA[KS규격/기계요소]]></category>
		<category><![CDATA[Counterbore]]></category>
		<category><![CDATA[Countersink]]></category>
		<category><![CDATA[Fasteners]]></category>
		<category><![CDATA[KS규격]]></category>
		<category><![CDATA[Machining]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[나사가공]]></category>
		<category><![CDATA[둥근머리나사]]></category>
		<category><![CDATA[접시머리나사]]></category>
		<category><![CDATA[카운터보어]]></category>
		<category><![CDATA[카운터싱크]]></category>
		<guid isPermaLink="false">https://myengnote.com/machining-differences-round-vs-countersunk-screws/</guid>

					<description><![CDATA[기계 조립의 정밀도를 결정짓는 나사 머리 형상별 체결부 가공법의 핵심 차이를 분석합니다. 실무에서 빈번하게 발생하는 카운터보어와 카운터싱크 설계 오류 방지 노하우를 공유합니다.... <a href="https://myengnote.com/machining-differences-round-vs-countersunk-screws/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[<p>벌써 십수 년 전의 일이지만, 자동차 부품의 고속 검사 라인에서 발생했던 한 사건이 아직도 생생합니다. 당시 분당 수백 개의 부품을 처리하던 고속 슬라이드 유닛의 고정부에서 원인 모를 진동과 위치 이탈이 반복되었습니다. 정밀 검사 결과, 원인은 단순했습니다. 가공 도면에는 접시머리 나사를 사용하도록 되어 있었으나, 실제 현장에서는 가공 편의성을 위해 둥근머리 나사를 사용하고 무리하게 조여놓았던 것이었습니다. 이로 인해 나사 머리가 부품 간의 간섭을 일으켰고, 반복되는 왕복 운동의 관성을 견디지 못한 체결부가 결국 파손되었습니다. 이 사건으로 인한 라인 정지 비용은 수천만 원에 달했으며, 이는 나사 하나를 설계할 때 체결부 가공 방식을 이해하는 것이 얼마나 중요한지를 뼈저리게 느끼게 해준 계기가 되었습니다. 우리가 흔히 사용하는 나사는 크게 머리 모양에 따라 둥근머리와 접시머리로 나뉩니다. 이 두 가지는 단순히 외관상의 차이가 아니라, 힘의 분산 방식과 체결 후의 표면 상태, 그리고 무엇보다 체결되는 모재의 가공 방식에서 근본적인 차이를 보입니다. 둥근머리 나사는 나사 머리가 모재 표면 위로 돌출되는 구조를 가집니다. 따라서 머리 부분이 외부로 드러나도 상관없거나 오히려 그 돌출부를 이용해 부품을 누르는 힘을 극대화해야 할 때 주로 사용합니다. 반면 접시머리 나사는 체결 후 머리 윗면이 모재의 표면과 일치하도록 설계됩니다. 이는 공기 역학적 특성이 중요하거나, 나사 체결부 위로 다른 부품이 미끄러지듯 이동해야 하는 슬라이드 면 등에 필수적입니다. </p>
<div style="border-left: 5px solid #3b82f6; background-color: #eff6ff; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"><span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d8.png" alt="📘" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="font-weight: bold; color: #1e40af; font-size: 1.2em;">핵심 요약</span></div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">둥근머리 나사는 평평한 바닥면을 가진 <strong>카운터보어(자리파기)</strong> 가공이 필요하고, 접시머리 나사는 원추형 경사면을 가진 <strong>카운터싱크(접시자리파기)</strong> 가공이 필수적입니다. 이 두 가공 방식의 혼용은 체결력 저하와 나사 머리 파손의 주원인이 됩니다.</div>
</p>
</div>
<p> 둥근머리 나사를 위한 가공, 즉 자리파기는 엔드밀이나 전용 드릴을 사용하여 나사 머리가 들어갈 원통형 공간을 만드는 공정입니다. 이때 가장 중요한 것은 바닥면의 평탄도입니다. 나사 머리 아랫면이 모재와 닿는 면적이 넓을수록 압축 응력이 고르게 분산되어 풀림 방지 효과가 커집니다. 만약 자리파기 구멍의 바닥이 경사지거나 거칠다면, 체결 시 나사가 한쪽으로 쏠리면서 축력이 불균형해지고 결국 나사가 부러지거나 나사산이 뭉개지는 현상이 발생합니다. 반대로 접시머리 나사는 머리 자체가 90도 또는 60도, 120도 등의 일정한 테이퍼 각도를 가지고 있습니다. 이를 수용하기 위한 가공이 바로 접시자리파기입니다. 이 가공의 핵심은 각도의 일치성입니다. <strong>KS B 1007</strong> 규격에 따르면 일반적인 접시머리 나사의 각도는 90도입니다. 만약 가공용 드릴의 각도가 나사 머리의 각도와 미세하게 다르다면, 선 접촉이나 점 접촉이 발생하게 됩니다. 이는 진동이 잦은 환경에서 나사 머리의 경사면을 따라 응력이 집중되어 미세 균열을 유발하는 원인이 됩니다. </p>
<h2>실무 필드 로그 및 분석 (Field Log &#038; Analysis)</h2>
<p>최근 한 정밀 전자 부품 조립 라인에서 발생한 장비 안정성 문제를 진단한 기록입니다.</p>
<ul>
<li><strong>설비 정보</strong>: 반도체 후공정 분류용 고속 모듈 (Mitsubishi 제어 시스템)</li>
<li><strong>관찰된 문제</strong>: 가동 48시간 이후 센서 브래킷의 미세 유격(약 1.5mm) 발생 및 위치 결정 정밀도 하락.</li>
<li><strong>진단 내용</strong>: M4 접시머리 나사의 카운터싱크 깊이 부족으로 나사 머리가 표면 위로 약 0.2mm 돌출되어 인접 슬라이딩 가이드와 간섭 발생.</li>
<li><strong>물리적 원인</strong>: 드릴 이송 깊이 설정 오류로 인한 체결 면적 40% 감소. 반복적인 진동 에너지(150Hz)가 전단 방향으로 집중되어 체결 토크 상실.</li>
<li><strong>조치 및 효과</strong>: 모든 체결부를 <strong>KS B 0407</strong> 표준에 맞춘 정밀 카운터싱크 가공으로 수정. 가동 중단 시간이 월 평균 12시간에서 0.5시간으로 감소하여 월간 약 5천만 원의 생산 손실 방지.</li>
</ul>
<div style="border-left: 5px solid #f59e0b; background-color: #fffbeb; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"><span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="font-weight: bold; color: #92400e; font-size: 1.2em;">현장 전문가의 팁</span></div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">접시머리 나사 가공 시에는 반드시 나사 머리의 직경보다 약 0.2~0.3mm 정도 더 넓게 가공하는 것이 좋습니다. 이는 소재의 열팽창이나 가공 오차로 인해 나사 머리가 표면 밖으로 튀어나와 다른 부품과 간섭을 일으키는 것을 방지하는 실무적인 노하우입니다.</div>
</p>
</div>
<p> 가공 방식의 차이는 공구 선정에서도 나타납니다. 둥근머리 나사용 자리파기는 일반적인 엔드밀로도 충분히 가공이 가능하지만, 접시머리 가공은 전용 카운터싱크 드릴을 사용하는 것이 원칙입니다. 가끔 현장에서 일반 드릴의 끝부분 경사각(보통 118도)을 그대로 이용하여 접시머리 나사를 체결하는 경우가 있는데, 이는 매우 위험한 도박입니다. 90도 나사 머리가 118도 구멍에 들어가면 오직 머리 윗부분의 모서리만 모재에 닿게 되어 체결력이 극도로 불안정해집니다. 또한, 소재의 두께에 따른 제약도 고려해야 합니다. 판재가 너무 얇은 경우 접시자리파기를 하면 구멍 주변의 강도가 급격히 약해지거나, 아예 나사가 판재를 뚫고 지나갈 수 있습니다. 이럴 때는 접시머리 대신 둥근머리 나사를 사용하거나, 소재를 국부적으로 눌러서 모양을 만드는 <strong>디플링(Dimpling)</strong> 공법을 검토해야 합니다. 기계 설계에서 &#8220;나사 하나쯤이야&#8221;라는 생각은 금물입니다. </p>
<div style="overflow-x: auto; white-space: nowrap; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); margin: 20px 0; border: 1px solid #e5e7eb;">
<table style="border-collapse: collapse; width: 100%; min-width: 700px; font-size: 15px; text-align: left; background-color: #ffffff;">
<thead>
<tr style="background-color: #1f2937; color: #ffffff;">
<th style="padding: 15px; border-bottom: 3px solid #3b82f6; font-weight: bold; text-transform: uppercase;">구분</th>
<th style="padding: 15px; border-bottom: 3px solid #10b981; font-weight: bold; text-transform: uppercase;">둥근머리 나사</th>
<th style="padding: 15px; border-bottom: 3px solid #f59e0b; font-weight: bold; text-transform: uppercase;">접시머리 나사</th>
</tr>
</thead>
<tbody>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">가공 방식</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">카운터보어 (원통형 자리파기)</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">카운터싱크 (원추형 자리파기)</td>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">가공 공구</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">엔드밀, 카운터보어 드릴</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">카운터싱크 전용 드릴 (90도)</td>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">주요 이점</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">강력한 클램핑력, 와셔 사용 용이</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">표면 돌출 없음, 자동 중심 맞춤</td>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">주의 사항</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">바닥면의 평탄도 확보 필수</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">나사 머리 각도와 가공 각도 일치</td>
</tr>
</tbody>
</table>
</div>
<p> 초보 엔지니어들이 흔히 하는 실수 중 하나는 나사의 길이를 선정할 때입니다. 둥근머리 나사는 머리 아랫부분부터 끝까지를 길이로 측정하지만, 접시머리 나사는 머리 윗면부터 끝까지를 전체 길이로 산정합니다. 이 사소한 차이를 인지하지 못해 가공 깊이가 깊어지거나 나사가 모재를 관통하여 내부 부품을 타격하는 사고가 빈번합니다. 특히 정밀 기계 조립에서는 이러한 미세한 치수 차이가 장비의 수명을 결정짓는 중요한 변수가 됩니다. </p>
<div style="border-left: 5px solid #ef4444; background-color: #fef2f2; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"><span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="font-weight: bold; color: #991b1b; font-size: 1.2em;">주의사항</span></div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">접시머리 나사를 체결할 때 전동 드라이버의 토크를 너무 높게 설정하지 마십시오. 접시머리는 <strong>쐐기 작용</strong>을 하기 때문에 과도한 토크는 모재의 구멍 주변을 벌어지게 하거나 피로 파괴를 앞당기는 원인이 됩니다.</div>
</p>
</div>
<p> 결론적으로, 둥근머리 나사는 &#8216;힘&#8217;의 상징이며 접시머리 나사는 &#8216;공간과 정밀도&#8217;의 상징이라고 할 수 있습니다. 설계를 할 때는 단순히 이뻐 보여서 접시머리를 선택하는 것이 아니라, 체결부의 두께, 진동의 유무, 상부 부품과의 간섭 여부를 종합적으로 판단해야 합니다. 진동이 심한 부위에는 가급적 둥근머리 나사와 스프링 와셔를 조합한 카운터보어 설계를 우선시하고, 센서가 이동하거나 부드러운 표면 마감이 필요한 곳에는 정밀한 카운터싱크 가공이 동반된 접시머리 나사를 채택하는 것이 정석입니다. <a href="https://myengnote.com/importance-of-pilot-holes-in-assembly-guide/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">조립의 기초, 파일럿 구멍의 중요성</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span></a><a href="https://myengnote.com/ph1-ph2-screwdriver-size-mismatch-wear/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">십자 드라이버 PH 규격 미준수와 나사산 마모</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span></a> </p>
<h2>0. 연관글</h2>
<p><!-- START_SIMULATOR_LINK_CARD_torque_power --><a href="https://myengnote.com/torque-power-converter-simulator/" target="_blank" rel="noopener noreferrer" class="eng-simulator-card" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ee.png" alt="🧮" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #10b981; font-weight: bold; margin-bottom: 4px;">실시간 공학 시뮬레이터 추천</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">회전 동력-토크 변환 계산기 &#038; 실시간 2D 전달 시뮬레이터</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #10b981; font-size: 24px; font-weight: bold;">→</span></a><!-- END_SIMULATOR_LINK_CARD_torque_power --><a href="https://myengnote.com/importance-of-diagonal-bolting-sequence-distortion/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">볼트 체결 순서와 조립 왜곡의 상관관계</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span></a></p>
<hr style="border: 0; border-top: 1px solid #eee; margin: 40px 0 20px 0;">
<p style="text-align: center; font-size: 0.85em; color: #888; margin-bottom: 20px;">
    본 콘텐츠는 저작권법의 보호를 받으며, 무단 전재 및 재배포를 금지합니다.<br />
    Copyright 2026. 동동 All rights reserved.
</p>
<p><!-- Protection Scripts --></p>
<div id="protection-script" style="display:none;">
<script>
document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
    alert('이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.');
});
document.addEventListener('keydown', function(e) {
    if (e.ctrlKey && (e.key === 'c' || e.key === 'u' || e.key === 'a')) {
        e.preventDefault();
        alert('무단 복제를 금지합니다.');
    }
});
</script></p>
<style>
.entry-content {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
</style>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/machining-differences-round-vs-countersunk-screws/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>공압 실린더 행정 선정의 기초 (Definition of Pneumatic Cylinder Stroke)</title>
		<link>https://myengnote.com/pneumatic-cylinder-stroke-definition-selection-guide/</link>
					<comments>https://myengnote.com/pneumatic-cylinder-stroke-definition-selection-guide/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Thu, 07 May 2026 10:48:05 +0000</pubDate>
				<category><![CDATA[배관/유공압]]></category>
		<category><![CDATA[Pneumatic]]></category>
		<category><![CDATA[Stroke]]></category>
		<category><![CDATA[공압실린더]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[실린더선정]]></category>
		<category><![CDATA[행정]]></category>
		<guid isPermaLink="false">https://myengnote.com/pneumatic-cylinder-stroke-definition-selection-guide/</guid>

					<description><![CDATA[공압 실린더 선정 시 가장 기본이 되는 행정의 개념과 실무적인 고려 사항을 다룹니다. 행정 거리 결정 오류가 장비 성능과 내구성에 미치는 영향을 현장 사례와 함께 상세히 분석합니다.... <a href="https://myengnote.com/pneumatic-cylinder-stroke-definition-selection-guide/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[<p>지금도 생생하게 기억나는 현장의 기억이 있습니다. 자동차 부품 조립 라인의 자동화 설비 구축 당시, 실린더의 행정 거리를 단 5mm 잘못 산정한 것만으로 전체 공정의 택트 타임이 무너지고, 결국 고가의 실린더가 파손되었던 사건입니다. 공압 실린더에서 행정, 즉 스트로크는 피스톤이 이동할 수 있는 최대 거리를 의미하며, 이는 장비의 물리적인 가동 범위를 결정하는 가장 핵심적인 요소입니다. 단순히 카탈로그에서 숫자를 고르는 것 이상의 정밀한 계산과 물리적 이해가 뒷받침되지 않으면, 기계는 곧 비명을 지르게 됩니다. </p>
<h2>실무 필드 로그 및 분석 (Field Log &#038; Analysis)</h2>
<p>작년 가을, 한 대형 가전기기 조립 라인에서 발생한 문제입니다. 해당 공정에는 SMC 사의 공압 실린더 모델 CP96SD63-150C가 장착되어 있었습니다. 이 실린더는 팔레트를 정지시키고 정위치로 밀어주는 역할을 수행하고 있었는데, 가동 후 불과 2주 만에 실린더 로드 끝부분의 나사산이 마모되고 내부 완충 기구가 파손되는 현상이 보고되었습니다.</p>
<p>현장에서 정밀 진단을 실시한 결과, 설계 데이터상의 행정 거리는 150mm였으나, 실제 작업물이 멈춰야 하는 물리적 지점은 147.2mm였습니다. 즉, 실린더의 피스톤이 내부 끝단에 닿기 전에 외부 스토퍼에 의해 강제로 멈춰지고 있었던 것입니다. 공압 실린더는 이동 끝단에서 공기의 압축성을 이용해 충격을 흡수해야 하는데, 행정 설정 오류로 인해 피스톤이 운동 에너지를 고스란히 로드와 외부 구조물에 전달하고 있었습니다. 85Hz 수준의 고주파 진동이 장비 전체로 퍼지고 있었으며, 이로 인해 발생한 가동 중단 비용은 시간당 수천만 원에 달했습니다.</p>
<p>이 문제는 단순한 수치 오차를 넘어, <strong>KS B ISO 4393(공압 실린더의 행정 시리즈)</strong> 규격에서 정의하는 이론적 행정과 실제 유효 행정의 차이를 간과했기 때문에 발생했습니다. 결국 실린더의 행정을 140mm로 하향 조정하고, 부족한 거리는 로드 엔드 어댑터를 통해 보정함으로써 충격 흡수 기능을 정상화할 수 있었습니다. 이를 통해 장비 유지보수 비용을 연간 15% 이상 절감하는 성과를 거두었습니다.</p>
<h2>행정의 정의와 물리적 메커니즘</h2>
<p>행정은 피스톤의 &#8216;출발점&#8217;과 &#8216;도착점&#8217; 사이의 거리입니다. 하지만 공압이라는 유체의 특성을 고려하면 이는 단순한 길이 이상의 의미를 가집니다. 공압 실린더 내부에서는 압축 공기가 피스톤 단면적에 작용하여 힘(F = P × A)을 발생시키고, 이 힘이 일정한 거리 동안 작용하면서 운동 에너지를 형성합니다.</p>
<p>이때 우리가 반드시 고려해야 할 것이 이론적 행정과 실제 필요 행정의 구분입니다. 기구 설계자가 100mm의 이동이 필요하다고 해서 딱 100mm 행정의 실린더를 선정하는 것은 위험한 도박입니다. 기계적인 조립 오차, 부품의 열팽창, 그리고 장시간 사용에 따른 위치 변화를 고려하면 반드시 5~10mm 정도의 <strong>여유 행정</strong>을 두는 것이 현명합니다.</p>
<div style="border-left: 5px solid #3b82f6; background-color: #eff6ff; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"> <span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d8.png" alt="📘" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> <span style="font-weight: bold; color: #1e40af; font-size: 1.2em;">핵심 요약</span> </div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;"> 공압 실린더의 행정은 단순히 이동 거리가 아니라, 위치 제어의 정밀도와 내구성을 결정짓는 물리적 한계치입니다. 적절한 행정 선정은 설비의 에너지 효율 및 수명과 직결됩니다. </div>
</div>
<p>행정이 길어질수록 실린더 로드에 가해지는 횡하중에 취약해집니다. 로드가 길게 뻗어 나올수록 지렛대 원리에 의해 내부 가이드와 씰에 가해지는 마찰력이 기하급수적으로 증가하기 때문입니다. 이는 곧 작동 불능이나 압축 공기 누설로 이어집니다. 따라서 긴 행정이 필요한 경우에는 실린더의 튜브 내경을 키우거나 별도의 외부 가이드를 설치하여 로드의 굽힘 강성을 확보해야 합니다.</p>
<h2>이론과 현실의 간극을 메우는 방법</h2>
<p>현장에서 흔히 하는 실수 중 하나는 실린더의 행정 끝단을 기계적인 정지점으로 사용하는 것입니다. 실린더 내부의 완충 기구(Cushion)는 피스톤이 커버에 부딪힐 때의 충격을 줄여주지만, 이는 보조적인 수단일 뿐입니다. 고속 작동이나 중량물 운반 시에는 실린더의 행정 범위를 모두 사용하기보다는, 외부 스토퍼나 쇼크 업쇼버를 활용해 물리적인 정지 위치를 잡아주는 것이 장비 수명 연장의 비결입니다.</p>
<p>또한, 행정 거리에 따른 공기 소모량도 계산에 넣어야 합니다. 행정이 길어질수록 한 번의 왕복에 필요한 공기의 부피가 커지며, 이는 공압 시스템 전체의 압력 강하를 유발할 수 있습니다. 시스템의 응답성을 높이려면 필요한 최소한의 행정만을 사용하는 것이 효율적입니다. 이를 위해 설계 단계에서 공압 매니폴드 블록의 역할을 정확히 이해하고, 공기의 흐름을 최적화하는 배관 설계가 선행되어야 합니다.</p>
<div style="border-left: 5px solid #ef4444; background-color: #fef2f2; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"> <span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> <span style="font-weight: bold; color: #991b1b; font-size: 1.2em;">주의사항</span> </div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;"> 실린더 행정이 1000mm를 초과하는 장행정 모델의 경우, 로드의 자중으로 인한 처짐 현상이 발생합니다. 반드시 지지 기구나 가이드 레일을 설계에 반영하십시오. </div>
</div>
<h2>초보 엔지니어들이 흔히 하는 실수와 대책</h2>
<p>신입 엔지니어들은 종종 실린더를 선정할 때 로드 끝단의 나사산 길이를 행정 거리와 혼동하곤 합니다. 행정은 순수하게 피스톤이 움직이는 거리이며, 로드 엔드의 나사산이나 부착물 치수는 별도로 관리해야 합니다. 특히 조립 시에는 원터치 피팅의 체결 상태를 명확히 확인하여, 행정 가동 중 발생하는 진동에 의해 호스가 이탈되는 사고를 미연에 방지해야 합니다.</p>
<p>또한, 모터 기반의 액추에이터와 공압 실린더를 동일한 시각으로 봐서는 안 됩니다. 공압은 중간 정지가 어렵고 양 끝단의 행정 제어에 특화되어 있습니다. 따라서 정밀한 다점 위치 제어가 필요한 곳에 무리하게 장행정 공압 실린더를 적용하는 것은 제어 난이도를 높이고 유지보수 비용을 증가시키는 원인이 됩니다.</p>
<div style="border-left: 5px solid #f59e0b; background-color: #fffbeb; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;"> <span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> <span style="font-weight: bold; color: #92400e; font-size: 1.2em;">현장 전문가의 팁</span> </div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;"> 실린더 행정을 선정할 때는 항상 센서의 감지 위치를 고려하십시오. 오토 스위치가 감지할 수 있는 최소 행정 거리가 카탈로그에 명시되어 있으므로 이를 반드시 확인해야 합니다. </div>
</div>
<h2>결론 및 제언</h2>
<p>공압 실린더의 행정은 단순한 &#8216;길이&#8217;가 아니라, 장비의 <strong>신뢰성</strong>을 결정짓는 척도입니다. 물리적인 에너지 흐름을 이해하고, 여유 치수를 확보하며, 외부 환경에 따른 변화를 예측하는 것만이 완벽한 설계를 가능하게 합니다. 이론적인 계산값에 안주하지 않고 실제 조립 환경에서의 간섭 조건과 부하의 관성 모멘트를 시뮬레이션하는 습관이 중요합니다. 행정 선정의 기본을 지키는 것, 그것이 바로 다운타임 없는 강건한 설비를 만드는 첫걸음입니다.</p>
<div style="overflow-x: auto; white-space: nowrap;">
<div style="overflow-x: auto; white-space: nowrap; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); margin: 20px 0; border: 1px solid #e5e7eb;">
<table style="border-collapse: collapse; width: 100%; min-width: 700px; font-size: 15px; text-align: left; background-color: #ffffff;">
<tr style="background-color: #f3f4f6;">
<th style="padding: 15px; border-bottom: 3px solid #4b5563; background-color: #1f2937; color: #ffffff; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em;">구분</th>
<th style="padding: 15px; border-bottom: 3px solid #3b82f6; background-color: #1f2937; color: #ffffff; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em;">표준 행정</th>
<th style="padding: 15px; border-bottom: 3px solid #10b981; background-color: #1f2937; color: #ffffff; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em;">장행정</th>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">범위</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">50mm ~ 500mm</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">600mm 이상</td>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">주요 고려사항</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">완충 효율, 센서 감지</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">로드 처짐, 좌굴 강도, 가이드 보강</td>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">추천 적용</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">일반 클램핑, 푸싱</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">이송 장치, 리프트</td>
</tr>
</table>
</div>
</div>
<h2>0. 연관글</h2>
<p><!-- START_SIMULATOR_LINK_CARD_pneumatic_cylinder --><a href="https://myengnote.com/pneumatic-cylinder-air-consumption-force-calculator/" target="_blank" rel="noopener noreferrer" class="eng-simulator-card" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ee.png" alt="🧮" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #10b981; font-weight: bold; margin-bottom: 4px;">실시간 공학 시뮬레이터 추천</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">공압 실린더 공기 소비량 계산기 &#038; 실시간 2D 물리 시뮬레이터</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #10b981; font-size: 24px; font-weight: bold;">→</span></a><!-- END_SIMULATOR_LINK_CARD_pneumatic_cylinder --><a href="https://myengnote.com/importance-of-fully-inserting-hose-in-one-touch-fittings/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"> <span style="display: table-cell; vertical-align: middle;"> <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> <span style="display: block; overflow: hidden;"> <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span> <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">원터치 피팅 호스 조립 시 끝까지 밀어 넣어야 하는 이유</span> </span> </span> <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span><br />
</a><a href="https://myengnote.com/motor-vs-actuator-application-differences/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"> <span style="display: table-cell; vertical-align: middle;"> <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> <span style="display: block; overflow: hidden;"> <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span> <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">모터와 액추에이터의 용도별 차이점</span> </span> </span> <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span><br />
</a><a href="https://myengnote.com/pneumatic-manifold-block-role-structure-guide/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"> <span style="display: table-cell; vertical-align: middle;"> <span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> <span style="display: block; overflow: hidden;"> <span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span> <span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">공압 매니폴드 블록의 역할과 내부 구조 이해하기</span> </span> </span> <span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span><br />
</a></p>
<hr style="border: 0; border-top: 1px solid #eee; margin: 40px 0 20px 0;">
<p style="text-align: center; font-size: 0.85em; color: #888; margin-bottom: 20px;">
    본 콘텐츠는 저작권법의 보호를 받으며, 무단 전재 및 재배포를 금지합니다.<br />
    Copyright 2026. 동동 All rights reserved.
</p>
<p><!-- Protection Scripts --></p>
<div id="protection-script" style="display:none;">
<script>
document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
    alert('이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.');
});
document.addEventListener('keydown', function(e) {
    if (e.ctrlKey && (e.key === 'c' || e.key === 'u' || e.key === 'a')) {
        e.preventDefault();
        alert('무단 복제를 금지합니다.');
    }
});
</script></p>
<style>
.entry-content {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
</style>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/pneumatic-cylinder-stroke-definition-selection-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
