web-artifacts-builder

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Web Artifacts Builder Skill

Web Artifacts Builder Skill

Overview

概述

Create self-contained, interactive web applications as single HTML files. These artifacts require no server, no build process, and can be shared as standalone files that run in any modern browser.
创建独立的交互式Web应用并打包为单个HTML文件。这些工件无需服务器、无需构建流程,可作为独立文件分享,在任何现代浏览器中运行。

When to Use

适用场景

  • Creating interactive demos or prototypes
  • Building standalone calculators or tools
  • Data visualization dashboards
  • Interactive documentation
  • Shareable proof-of-concepts
  • Any web experience that needs to work offline
  • 创建交互式演示或原型
  • 构建独立计算器或工具
  • 数据可视化仪表盘
  • 交互式文档
  • 可分享的概念验证项目
  • 任何需要离线运行的Web体验

Quick Start

快速开始

  1. Create single HTML file with all CSS/JS inline
  2. Use CDN for libraries (Chart.js, Plotly, etc.)
  3. Embed data directly as JSON or JS objects
  4. Test locally by opening file in browser
  5. Share as single file attachment
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Web Artifact</title>
  <style>
    body { font-family: system-ui; padding: 20px; }
    .btn { padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; }
  </style>
</head>
<body>
  <h1>Interactive Tool</h1>
  <button class="btn" onclick="calculate()">Calculate</button>
  <div id="result"></div>
  <script>
    function calculate() {
      document.getElementById('result').textContent = 'Result: ' + (Math.random() * 100).toFixed(2);
    }
  </script>
</body>
</html>
  1. 创建单个HTML文件,将所有CSS/JS内联其中
  2. 使用CDN引入库(Chart.js、Plotly等)
  3. 直接嵌入数据为JSON或JS对象
  4. 本地测试:在浏览器中打开文件
  5. 分享:作为单个文件附件发送
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Web Artifact</title>
  <style>
    body { font-family: system-ui; padding: 20px; }
    .btn { padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; }
  </style>
</head>
<body>
  <h1>Interactive Tool</h1>
  <button class="btn" onclick="calculate()">Calculate</button>
  <div id="result"></div>
  <script>
    function calculate() {
      document.getElementById('result').textContent = 'Result: ' + (Math.random() * 100).toFixed(2);
    }
  </script>
</body>
</html>

Core Principles

核心原则

Self-Contained Architecture

独立架构

Everything in one HTML file:
  • HTML structure
  • CSS styles (inline or in
    <style>
    tags)
  • JavaScript functionality (inline or in
    <script>
    tags)
  • Data (embedded JSON or JavaScript objects)
  • Assets (inline SVG, base64 images, or CDN links)
所有内容都在一个HTML文件中:
  • HTML结构
  • CSS样式(内联或在
    <style>
    标签中)
  • JavaScript功能(内联或在
    <script>
    标签中)
  • 数据(嵌入的JSON或JavaScript对象)
  • 资源(内联SVG、base64图片或CDN链接)

No External Dependencies Required

无需外部依赖

html
<!-- Use CDN for libraries when needed -->
<script src="https://cdn.jsdelivr.net/npm/library@version"></script>

<!-- Or embed everything inline -->
<script>
// All JavaScript here
</script>
html
<!-- 需要时使用CDN引入库 -->
<script src="https://cdn.jsdelivr.net/npm/library@version"></script>

<!-- 或者将所有内容内联 -->
<script>
// 所有JavaScript代码写在这里
</script>

Basic Template

基础模板

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Artifact</title>
    <style>
        /* Reset and base styles */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            line-height: 1.6;
            color: #333;
            background: #f5f5f5;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }

        /* Component styles */
        .card {
            background: white;
            border-radius: 8px;
            padding: 24px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            margin-bottom: 20px;
        }

        .btn {
            display: inline-block;
            padding: 10px 20px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            transition: background 0.2s;
        }

        .btn:hover {
            background: #0056b3;
        }

        /* Responsive */
        @media (max-width: 768px) {
            .container {
                padding: 10px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="card">
            <h1>Web Artifact</h1>
            <p>Self-contained interactive application</p>
            <button class="btn" onclick="handleClick()">Click Me</button>
            <div id="output"></div>
        </div>
    </div>

    <script>
        // Application state
        const state = {
            count: 0
        };

        // Event handlers
        function handleClick() {
            state.count++;
            render();
        }

        // Render function
        function render() {
            document.getElementById('output').innerHTML = `
                <p>Clicked ${state.count} times</p>
            `;
        }

        // Initialize
        document.addEventListener('DOMContentLoaded', render);
    </script>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Artifact</title>
    <style>
        /* 重置和基础样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            line-height: 1.6;
            color: #333;
            background: #f5f5f5;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }

        /* 组件样式 */
        .card {
            background: white;
            border-radius: 8px;
            padding: 24px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            margin-bottom: 20px;
        }

        .btn {
            display: inline-block;
            padding: 10px 20px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            transition: background 0.2s;
        }

        .btn:hover {
            background: #0056b3;
        }

        /* 响应式设计 */
        @media (max-width: 768px) {
            .container {
                padding: 10px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="card">
            <h1>Web Artifact</h1>
            <p>独立交互式应用</p>
            <button class="btn" onclick="handleClick()">点击我</button>
            <div id="output"></div>
        </div>
    </div>

    <script>
        // 应用状态
        const state = {
            count: 0
        };

        // 事件处理器
        function handleClick() {
            state.count++;
            render();
        }

        // 渲染函数
        function render() {
            document.getElementById('output').innerHTML = `
                <p>已点击 ${state.count} 次</p>
            `;
        }

        // 初始化
        document.addEventListener('DOMContentLoaded', render);
    </script>
</body>
</html>

Common Artifact Types

常见工件类型

1. Interactive Dashboard

1. 交互式仪表盘

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: system-ui, sans-serif;
            background: #1a1a2e;
            color: #eee;
            min-height: 100vh;
        }
        .dashboard {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            padding: 20px;
            max-width: 1400px;
            margin: 0 auto;
        }
        .card {
            background: #16213e;
            border-radius: 12px;
            padding: 20px;
        }
        .stat-card {
            text-align: center;
        }
        .stat-value {
            font-size: 3em;
            font-weight: bold;
            color: #e94560;
        }
        .stat-label {
            color: #888;
            margin-top: 8px;
        }
        .chart-container {
            position: relative;
            height: 300px;
        }
        h1 {
            text-align: center;
            padding: 20px;
            color: #e94560;
        }
    </style>
</head>
<body>
    <h1>Analytics Dashboard</h1>
    <div class="dashboard">
        <div class="card stat-card">
            <div class="stat-value" id="users">0</div>
            <div class="stat-label">Active Users</div>
        </div>
        <div class="card stat-card">
            <div class="stat-value" id="revenue">$0</div>
            <div class="stat-label">Revenue</div>
        </div>
        <div class="card stat-card">
            <div class="stat-value" id="growth">0%</div>
            <div class="stat-label">Growth</div>
        </div>
        <div class="card" style="grid-column: span 2;">
            <h3 style="margin-bottom: 15px;">Weekly Trend</h3>
            <div class="chart-container">
                <canvas id="trendChart"></canvas>
            </div>
        </div>
        <div class="card">
            <h3 style="margin-bottom: 15px;">Distribution</h3>
            <div class="chart-container">
                <canvas id="pieChart"></canvas>
            </div>
        </div>
    </div>

    <script>
        // Embedded data
        const data = {
            users: 12847,
            revenue: 94520,
            growth: 23.5,
            weekly: [65, 72, 86, 81, 90, 95, 110],
            distribution: [35, 25, 20, 15, 5]
        };

        // Animate counting
        function animateValue(id, end, prefix = '', suffix = '') {
            const el = document.getElementById(id);
            const duration = 1500;
            const start = 0;
            const startTime = performance.now();

            function update(currentTime) {
                const elapsed = currentTime - startTime;
                const progress = Math.min(elapsed / duration, 1);
                const eased = 1 - Math.pow(1 - progress, 3);
                const current = Math.floor(start + (end - start) * eased);
                el.textContent = prefix + current.toLocaleString() + suffix;
                if (progress < 1) requestAnimationFrame(update);
            }
            requestAnimationFrame(update);
        }

        // Initialize charts
        document.addEventListener('DOMContentLoaded', () => {
            // Animate stats
            animateValue('users', data.users);
            animateValue('revenue', data.revenue, '$');
            animateValue('growth', data.growth, '', '%');

            // Line chart
            new Chart(document.getElementById('trendChart'), {
                type: 'line',
                data: {
                    labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
                    datasets: [{
                        label: 'Users',
                        data: data.weekly,
                        borderColor: '#e94560',
                        backgroundColor: 'rgba(233, 69, 96, 0.1)',
                        fill: true,
                        tension: 0.4
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: { legend: { display: false } },
                    scales: {
                        y: { grid: { color: '#333' }, ticks: { color: '#888' } },
                        x: { grid: { display: false }, ticks: { color: '#888' } }
                    }
                }
            });

            // Pie chart
            new Chart(document.getElementById('pieChart'), {
                type: 'doughnut',
                data: {
                    labels: ['Product A', 'Product B', 'Product C', 'Product D', 'Other'],
                    datasets: [{
                        data: data.distribution,
                        backgroundColor: ['#e94560', '#0f3460', '#16213e', '#533483', '#1a1a2e']
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: {
                        legend: { position: 'right', labels: { color: '#888' } }
                    }
                }
            });
        });
    </script>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: system-ui, sans-serif;
            background: #1a1a2e;
            color: #eee;
            min-height: 100vh;
        }
        .dashboard {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            padding: 20px;
            max-width: 1400px;
            margin: 0 auto;
        }
        .card {
            background: #16213e;
            border-radius: 12px;
            padding: 20px;
        }
        .stat-card {
            text-align: center;
        }
        .stat-value {
            font-size: 3em;
            font-weight: bold;
            color: #e94560;
        }
        .stat-label {
            color: #888;
            margin-top: 8px;
        }
        .chart-container {
            position: relative;
            height: 300px;
        }
        h1 {
            text-align: center;
            padding: 20px;
            color: #e94560;
        }
    </style>
</head>
<body>
    <h1>数据分析仪表盘</h1>
    <div class="dashboard">
        <div class="card stat-card">
            <div class="stat-value" id="users">0</div>
            <div class="stat-label">活跃用户数</div>
        </div>
        <div class="card stat-card">
            <div class="stat-value" id="revenue">$0</div>
            <div class="stat-label">营收</div>
        </div>
        <div class="card stat-card">
            <div class="stat-value" id="growth">0%</div>
            <div class="stat-label">增长率</div>
        </div>
        <div class="card" style="grid-column: span 2;">
            <h3 style="margin-bottom: 15px;">周度趋势</h3>
            <div class="chart-container">
                <canvas id="trendChart"></canvas>
            </div>
        </div>
        <div class="card">
            <h3 style="margin-bottom: 15px;">分布情况</h3>
            <div class="chart-container">
                <canvas id="pieChart"></canvas>
            </div>
        </div>
    </div>

    <script>
        // 嵌入的数据
        const data = {
            users: 12847,
            revenue: 94520,
            growth: 23.5,
            weekly: [65, 72, 86, 81, 90, 95, 110],
            distribution: [35, 25, 20, 15, 5]
        };

        // 数字动画效果
        function animateValue(id, end, prefix = '', suffix = '') {
            const el = document.getElementById(id);
            const duration = 1500;
            const start = 0;
            const startTime = performance.now();

            function update(currentTime) {
                const elapsed = currentTime - startTime;
                const progress = Math.min(elapsed / duration, 1);
                const eased = 1 - Math.pow(1 - progress, 3);
                const current = Math.floor(start + (end - start) * eased);
                el.textContent = prefix + current.toLocaleString() + suffix;
                if (progress < 1) requestAnimationFrame(update);
            }
            requestAnimationFrame(update);
        }

        // 初始化图表
        document.addEventListener('DOMContentLoaded', () => {
            // 动画展示统计数据
            animateValue('users', data.users);
            animateValue('revenue', data.revenue, '$');
            animateValue('growth', data.growth, '', '%');

            // 折线图
            new Chart(document.getElementById('trendChart'), {
                type: 'line',
                data: {
                    labels: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
                    datasets: [{
                        label: '用户数',
                        data: data.weekly,
                        borderColor: '#e94560',
                        backgroundColor: 'rgba(233, 69, 96, 0.1)',
                        fill: true,
                        tension: 0.4
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: { legend: { display: false } },
                    scales: {
                        y: { grid: { color: '#333' }, ticks: { color: '#888' } },
                        x: { grid: { display: false }, ticks: { color: '#888' } }
                    }
                }
            });

            // 饼图
            new Chart(document.getElementById('pieChart'), {
                type: 'doughnut',
                data: {
                    labels: ['产品A', '产品B', '产品C', '产品D', '其他'],
                    datasets: [{
                        data: data.distribution,
                        backgroundColor: ['#e94560', '#0f3460', '#16213e', '#533483', '#1a1a2e']
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: {
                        legend: { position: 'right', labels: { color: '#888' } }
                    }
                }
            });
        });
    </script>
</body>
</html>

2. Interactive Calculator/Tool

2. 交互式计算器/工具

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Calculator Tool</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: system-ui, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }
        .calculator {
            background: white;
            border-radius: 16px;
            padding: 30px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3);
            width: 100%;
            max-width: 400px;
        }
        h1 {
            color: #333;
            margin-bottom: 20px;
            text-align: center;
        }
        .form-group {
            margin-bottom: 20px;
        }
        label {
            display: block;
            margin-bottom: 8px;
            color: #555;
            font-weight: 500;
        }
        input, select {
            width: 100%;
            padding: 12px;
            border: 2px solid #e0e0e0;
            border-radius: 8px;
            font-size: 16px;
            transition: border-color 0.2s;
        }
        input:focus, select:focus {
            outline: none;
            border-color: #667eea;
        }
        .btn {
            width: 100%;
            padding: 14px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
        }
        .result {
            margin-top: 20px;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 8px;
            text-align: center;
            display: none;
        }
        .result.show { display: block; }
        .result-value {
            font-size: 2.5em;
            font-weight: bold;
            color: #667eea;
        }
        .result-label {
            color: #666;
            margin-top: 8px;
        }
    </style>
</head>
<body>
    <div class="calculator">
        <h1>Savings Calculator</h1>
        <div class="form-group">
            <label for="principal">Initial Investment ($)</label>
            <input type="number" id="principal" value="10000" min="0">
        </div>
        <div class="form-group">
            <label for="monthly">Monthly Contribution ($)</label>
            <input type="number" id="monthly" value="500" min="0">
        </div>
        <div class="form-group">
            <label for="rate">Annual Interest Rate (%)</label>
            <input type="number" id="rate" value="7" min="0" max="100" step="0.1">
        </div>
        <div class="form-group">
            <label for="years">Investment Period (Years)</label>
            <input type="number" id="years" value="10" min="1" max="50">
        </div>
        <button class="btn" onclick="calculate()">Calculate</button>
        <div class="result" id="result">
            <div class="result-value" id="total">$0</div>
            <div class="result-label">Future Value</div>
            <div style="margin-top: 15px; color: #666;">
                <div>Total Contributions: <strong id="contributions">$0</strong></div>
                <div>Interest Earned: <strong id="interest">$0</strong></div>
            </div>
        </div>
    </div>

    <script>
        function calculate() {
            const principal = parseFloat(document.getElementById('principal').value) || 0;
            const monthly = parseFloat(document.getElementById('monthly').value) || 0;
            const rate = (parseFloat(document.getElementById('rate').value) || 0) / 100;
            const years = parseInt(document.getElementById('years').value) || 0;

            const monthlyRate = rate / 12;
            const months = years * 12;

            // Future value calculation
            let futureValue = principal * Math.pow(1 + monthlyRate, months);
            if (monthlyRate > 0) {
                futureValue += monthly * ((Math.pow(1 + monthlyRate, months) - 1) / monthlyRate);
            } else {
                futureValue += monthly * months;
            }

            const totalContributions = principal + (monthly * months);
            const interestEarned = futureValue - totalContributions;

            // Update display
            document.getElementById('total').textContent = formatCurrency(futureValue);
            document.getElementById('contributions').textContent = formatCurrency(totalContributions);
            document.getElementById('interest').textContent = formatCurrency(interestEarned);
            document.getElementById('result').classList.add('show');
        }

        function formatCurrency(value) {
            return new Intl.NumberFormat('en-US', {
                style: 'currency',
                currency: 'USD',
                minimumFractionDigits: 0,
                maximumFractionDigits: 0
            }).format(value);
        }

        // Calculate on input change
        document.querySelectorAll('input').forEach(input => {
            input.addEventListener('input', calculate);
        });

        // Initial calculation
        calculate();
    </script>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Calculator Tool</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: system-ui, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }
        .calculator {
            background: white;
            border-radius: 16px;
            padding: 30px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3);
            width: 100%;
            max-width: 400px;
        }
        h1 {
            color: #333;
            margin-bottom: 20px;
            text-align: center;
        }
        .form-group {
            margin-bottom: 20px;
        }
        label {
            display: block;
            margin-bottom: 8px;
            color: #555;
            font-weight: 500;
        }
        input, select {
            width: 100%;
            padding: 12px;
            border: 2px solid #e0e0e0;
            border-radius: 8px;
            font-size: 16px;
            transition: border-color 0.2s;
        }
        input:focus, select:focus {
            outline: none;
            border-color: #667eea;
        }
        .btn {
            width: 100%;
            padding: 14px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
        }
        .result {
            margin-top: 20px;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 8px;
            text-align: center;
            display: none;
        }
        .result.show { display: block; }
        .result-value {
            font-size: 2.5em;
            font-weight: bold;
            color: #666eea;
        }
        .result-label {
            color: #666;
            margin-top: 8px;
        }
    </style>
</head>
<body>
    <div class="calculator">
        <h1>储蓄计算器</h1>
        <div class="form-group">
            <label for="principal">初始投资金额(美元)</label>
            <input type="number" id="principal" value="10000" min="0">
        </div>
        <div class="form-group">
            <label for="monthly">每月定投金额(美元)</label>
            <input type="number" id="monthly" value="500" min="0">
        </div>
        <div class="form-group">
            <label for="rate">年利率(%)</label>
            <input type="number" id="rate" value="7" min="0" max="100" step="0.1">
        </div>
        <div class="form-group">
            <label for="years">投资期限(年)</label>
            <input type="number" id="years" value="10" min="1" max="50">
        </div>
        <button class="btn" onclick="calculate()">计算</button>
        <div class="result" id="result">
            <div class="result-value" id="total">$0</div>
            <div class="result-label">未来价值</div>
            <div style="margin-top: 15px; color: #666;">
                <div>总投入金额:<strong id="contributions">$0</strong></div>
                <div>赚取利息:<strong id="interest">$0</strong></div>
            </div>
        </div>
    </div>

    <script>
        function calculate() {
            const principal = parseFloat(document.getElementById('principal').value) || 0;
            const monthly = parseFloat(document.getElementById('monthly').value) || 0;
            const rate = (parseFloat(document.getElementById('rate').value) || 0) / 100;
            const years = parseInt(document.getElementById('years').value) || 0;

            const monthlyRate = rate / 12;
            const months = years * 12;

            // 未来价值计算公式
            let futureValue = principal * Math.pow(1 + monthlyRate, months);
            if (monthlyRate > 0) {
                futureValue += monthly * ((Math.pow(1 + monthlyRate, months) - 1) / monthlyRate);
            } else {
                futureValue += monthly * months;
            }

            const totalContributions = principal + (monthly * months);
            const interestEarned = futureValue - totalContributions;

            // 更新显示内容
            document.getElementById('total').textContent = formatCurrency(futureValue);
            document.getElementById('contributions').textContent = formatCurrency(totalContributions);
            document.getElementById('interest').textContent = formatCurrency(interestEarned);
            document.getElementById('result').classList.add('show');
        }

        function formatCurrency(value) {
            return new Intl.NumberFormat('en-US', {
                style: 'currency',
                currency: 'USD',
                minimumFractionDigits: 0,
                maximumFractionDigits: 0
            }).format(value);
        }

        // 输入变化时自动计算
        document.querySelectorAll('input').forEach(input => {
            input.addEventListener('input', calculate);
        });

        // 初始计算
        calculate();
    </script>
</body>
</html>

Best Practices

最佳实践

Performance

性能优化

  1. Minimize dependencies: Only include what you need
  2. Use CDN with version pinning:
    library@4.4.0
    not
    library@latest
  3. Lazy load when possible: Defer non-critical scripts
  4. Optimize images: Use SVG or base64 for small images
  1. 最小化依赖:只引入必需的内容
  2. 使用固定版本的CDN:使用
    library@4.4.0
    而非
    library@latest
  3. 按需懒加载:延迟加载非关键脚本
  4. 优化图片:对小图片使用SVG或base64格式

Accessibility

可访问性

html
<!-- Always include -->
<html lang="en">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- Use semantic HTML -->
<main>, <nav>, <article>, <section>, <header>, <footer>

<!-- Add ARIA labels -->
<button aria-label="Close dialog">x</button>

<!-- Ensure color contrast -->
/* Minimum 4.5:1 for normal text */
html
<!-- 务必包含 -->
<html lang="en">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- 使用语义化HTML -->
<main>, <nav>, <article>, <section>, <header>, <footer>

<!-- 添加ARIA标签 -->
<button aria-label="关闭对话框">x</button>

<!-- 确保颜色对比度 -->
/* 普通文本的对比度至少为4.5:1 */

Responsive Design

响应式设计

css
/* Mobile-first approach */
.container {
    padding: 10px;
}

@media (min-width: 768px) {
    .container {
        padding: 20px;
    }
}

@media (min-width: 1024px) {
    .container {
        max-width: 1200px;
        margin: 0 auto;
    }
}
css
/* 移动端优先的设计思路 */
.container {
    padding: 10px;
}

@media (min-width: 768px) {
    .container {
        padding: 20px;
    }
}

@media (min-width: 1024px) {
    .container {
        max-width: 1200px;
        margin: 0 auto;
    }
}

Common CDN Libraries

常用CDN库

html
<!-- Charts -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script src="https://cdn.plot.ly/plotly-2.27.0.min.js"></script>

<!-- UI Frameworks -->
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">

<!-- Utilities -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dayjs@1.11.10/dayjs.min.js"></script>

<!-- Animation -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.2/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js"></script>

<!-- 3D/Graphics -->
<script src="https://cdn.jsdelivr.net/npm/three@0.159.0/build/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>

<!-- Maps -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>

<!-- Markdown -->
<script src="https://cdn.jsdelivr.net/npm/marked@9.1.0/marked.min.js"></script>

<!-- Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
html
<!-- 图表库 -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script src="https://cdn.plot.ly/plotly-2.27.0.min.js"></script>

<!-- UI框架 -->
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">

<!-- 工具库 -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dayjs@1.11.10/dayjs.min.js"></script>

<!-- 动画库 -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.2/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js"></script>

<!-- 3D/图形库 -->
<script src="https://cdn.jsdelivr.net/npm/three@0.159.0/build/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>

<!-- 地图库 -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>

<!-- Markdown解析 -->
<script src="https://cdn.jsdelivr.net/npm/marked@9.1.0/marked.min.js"></script>

<!-- 图标库 -->
<script src="https://unpkg.com/lucide@latest"></script>

Execution Checklist

执行检查清单

  • All CSS and JS inline or from CDN
  • No server dependencies
  • Works offline (or gracefully degrades)
  • Responsive across devices
  • Accessible (ARIA labels, contrast, keyboard nav)
  • Data embedded or loaded from CDN
  • File size reasonable (< 500KB ideal)
  • Tested in multiple browsers
  • Clear user instructions
  • 所有CSS和JS均为内联或来自CDN
  • 无服务器依赖
  • 可离线运行(或优雅降级)
  • 在不同设备上具备响应式表现
  • 可访问性达标(ARIA标签、对比度、键盘导航)
  • 数据已嵌入或从CDN加载
  • 文件大小合理(理想情况下小于500KB)
  • 在多个浏览器中测试通过
  • 具备清晰的用户说明

Error Handling

错误处理

Common Issues

常见问题

Issue: CDN library not loading
  • Cause: Network issue or wrong URL
  • Solution: Pin version, add fallback, test offline
Issue: File doesn't open in browser
  • Cause: Browser blocking local file access
  • Solution: Use a simple HTTP server or data: URLs
Issue: Charts not rendering
  • Cause: DOM not ready when script runs
  • Solution: Use DOMContentLoaded event
Issue: Styles not applying
  • Cause: CSS specificity or load order
  • Solution: Use more specific selectors, check order
问题:CDN库加载失败
  • 原因:网络问题或URL错误
  • 解决方案:固定版本、添加降级方案、离线测试
问题:文件无法在浏览器中打开
  • 原因:浏览器阻止本地文件访问
  • 解决方案:使用简单的HTTP服务器或data: URL
问题:图表无法渲染
  • 原因:脚本运行时DOM尚未准备就绪
  • 解决方案:使用DOMContentLoaded事件
问题:样式未生效
  • 原因:CSS优先级或加载顺序问题
  • 解决方案:使用更具体的选择器、检查加载顺序

Metrics

指标要求

MetricTargetHow to Measure
File Size< 500 KBFile properties
Load Time< 2 secondsBrowser DevTools
Accessibility> 90Lighthouse
Mobile Usability100%Manual testing
Browser Support95%+caniuse.com
指标目标值测量方式
文件大小< 500 KB文件属性查看
加载时间< 2秒浏览器开发者工具
可访问性> 90分Lighthouse工具
移动端可用性100%手动测试
浏览器兼容性95%+caniuse.com查询

Sharing & Distribution

分享与分发

File Naming

文件命名规范

project-name_v1.0.html
dashboard_2024-01-15.html
calculator-tool.html
项目名称_v1.0.html
仪表盘_2024-01-15.html
计算器工具.html

Embedding Data

数据嵌入方式

javascript
// Embed JSON data directly
const DATA = {
    items: [...],
    config: {...}
};

// Or base64 encode binary data
const imageData = 'data:image/png;base64,iVBORw0KGgo...';
javascript
// 直接嵌入JSON数据
const DATA = {
    items: [...],
    config: {...}
};

// 或者对二进制数据进行base64编码
const imageData = 'data:image/png;base64,iVBORw0KGgo...';

Export Functionality

导出功能示例

javascript
function downloadData() {
    const data = JSON.stringify(state, null, 2);
    const blob = new Blob([data], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'export.json';
    a.click();
    URL.revokeObjectURL(url);
}
javascript
function downloadData() {
    const data = JSON.stringify(state, null, 2);
    const blob = new Blob([data], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'export.json';
    a.click();
    URL.revokeObjectURL(url);
}

Related Skills

相关技能

  • frontend-design - Advanced UI design
  • algorithmic-art - Generative visuals
  • theme-factory - Color and typography

  • frontend-design - 高级UI设计
  • algorithmic-art - 生成式视觉效果
  • theme-factory - 色彩与排版

Version History

版本历史

  • 2.0.0 (2026-01-02): Upgraded to v2 template - added Quick Start, When to Use, Execution Checklist, Error Handling, Metrics sections
  • 1.0.0 (2024-10-15): Initial release with basic template, dashboard, calculator, data visualization examples, CDN library references, best practices
  • 2.0.0 (2026-01-02): 升级到v2模板 - 新增快速开始、适用场景、执行检查清单、错误处理、指标要求章节
  • 1.0.0 (2024-10-15): 初始版本,包含基础模板、仪表盘、计算器、数据可视化示例、CDN库参考、最佳实践