| <!DOCTYPE html> |
| <html lang="ja"> |
|
|
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| |
| <script> |
| (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': |
| new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], |
| j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= |
| 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); |
| })(window,document,'script','dataLayer','GTM-PJXRKX3F'); |
| </script> |
| |
| <title>Scratch for school</title> |
| <link href="https://fonts.googleapis.com/css2?family=Yomogi&display=swap" rel="stylesheet"> |
| <style> |
| :root { |
| --primary-color: #4a90e2; |
| --primary-hover: #357ab7; |
| --accent-color: #00bfff; |
| --text-color: #333; |
| --bg-color: #f0f8ff; |
| --card-bg: #ffffff; |
| --border-color: #e0e0e0; |
| --shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
| --transition: all 0.3s ease; |
| --scrollbar-features: #4a90e2; |
| --scrollbar-video: #00bfff; |
| } |
| |
| |
| body { |
| scrollbar-width: none; |
| -ms-overflow-style: none; |
| overflow-x: hidden; |
| } |
| body::-webkit-scrollbar { |
| display: none; |
| } |
| |
| .scroll-progress { |
| position: fixed; |
| top: 0; |
| left: 0; |
| width: 0; |
| height: 3px; |
| background: linear-gradient(90deg, var(--scrollbar-features) 0%, var(--scrollbar-video) 100%); |
| z-index: 1000; |
| transition: width 0.1s ease-out; |
| } |
| |
| body { |
| margin: 0; |
| padding: 0; |
| font-family: 'Yomogi', cursive; |
| background-color: var(--bg-color); |
| color: var(--text-color); |
| line-height: 1.6; |
| scroll-behavior: smooth; |
| } |
| |
| |
| .header-container { |
| position: relative; |
| width: 100%; |
| height: 100vh; |
| overflow: hidden; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| text-align: center; |
| } |
| |
| .header-video { |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| object-fit: cover; |
| z-index: -1; |
| filter: brightness(0.5); |
| } |
| |
| .header-content { |
| position: relative; |
| z-index: 1; |
| color: white; |
| padding: 2rem; |
| max-width: 800px; |
| margin: 0 auto; |
| } |
| |
| |
| .loading-overlay { |
| position: fixed; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| background-color: var(--bg-color); |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| z-index: 9999; |
| opacity: 1; |
| transition: opacity 0.5s ease; |
| } |
| |
| .loading-overlay.hidden { |
| opacity: 0; |
| pointer-events: none; |
| } |
| |
| .loader { |
| width: 48px; |
| height: 48px; |
| border: 5px solid var(--primary-color); |
| border-bottom-color: transparent; |
| border-radius: 50%; |
| display: inline-block; |
| box-sizing: border-box; |
| animation: rotation 1s linear infinite; |
| } |
| |
| @keyframes rotation { |
| 0% { transform: rotate(0deg); } |
| 100% { transform: rotate(360deg); } |
| } |
| |
| h1 { |
| font-family: 'Playpen Sans Deva', cursive; |
| font-size: 3rem; |
| margin-bottom: 1rem; |
| color: white; |
| text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); |
| } |
| |
| p.description { |
| max-width: 800px; |
| margin: 0 auto 2rem; |
| font-size: 1.2rem; |
| line-height: 1.8; |
| color: white; |
| text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); |
| } |
| |
| .buttons { |
| display: flex; |
| justify-content: center; |
| gap: 1.5rem; |
| margin-bottom: 3rem; |
| flex-wrap: wrap; |
| } |
| |
| .buttons a { |
| font-family: 'Yomogi', cursive; |
| background-color: var(--primary-color); |
| color: white; |
| padding: 0.75rem 1.5rem; |
| border-radius: 50px; |
| text-decoration: none; |
| font-size: 1.1rem; |
| transition: var(--transition); |
| box-shadow: var(--shadow); |
| position: relative; |
| overflow: hidden; |
| } |
| |
| .buttons a:hover { |
| background-color: var(--primary-hover); |
| transform: translateY(-3px); |
| box-shadow: 0 6px 12px rgba(0,0,0,0.15); |
| } |
| |
| .buttons a::after { |
| content: ''; |
| position: absolute; |
| top: 50%; |
| left: 50%; |
| width: 5px; |
| height: 5px; |
| background: rgba(255, 255, 255, 0.5); |
| opacity: 0; |
| border-radius: 100%; |
| transform: scale(1, 1) translate(-50%); |
| transform-origin: 50% 50%; |
| } |
| |
| .buttons a:focus:not(:active)::after { |
| animation: ripple 0.6s ease-out; |
| } |
| |
| @keyframes ripple { |
| 0% { |
| transform: scale(0, 0); |
| opacity: 0.5; |
| } |
| 100% { |
| transform: scale(20, 20); |
| opacity: 0; |
| } |
| } |
| |
| section { |
| padding: 2rem; |
| max-width: 1000px; |
| margin: 0 auto; |
| opacity: 0; |
| transform: translateY(50px); |
| transition: opacity 0.8s ease, transform 0.8s ease; |
| } |
| |
| section.visible { |
| opacity: 1; |
| transform: translateY(0); |
| } |
| |
| section#features h2 { |
| font-size: 2.2rem; |
| margin-bottom: 1.5rem; |
| color: var(--primary-color); |
| position: relative; |
| padding-bottom: 0.5rem; |
| } |
| |
| section#features h2::after { |
| content: ''; |
| position: absolute; |
| bottom: 0; |
| left: 0; |
| width: 60px; |
| height: 3px; |
| background-color: var(--accent-color); |
| border-radius: 3px; |
| } |
| |
| |
| .feature-list { |
| background-color: var(--card-bg); |
| border-radius: 12px; |
| padding: 1.5rem; |
| box-shadow: var(--shadow); |
| margin-bottom: 2rem; |
| transition: var(--transition); |
| } |
| |
| .feature-list:hover { |
| transform: translateY(-5px); |
| box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); |
| } |
| |
| .feature-list > li { |
| font-weight: bold; |
| font-size: 1.2rem; |
| margin-bottom: 1rem; |
| color: var(--primary-color); |
| display: flex; |
| align-items: center; |
| } |
| |
| .feature-list > li::before { |
| content: '✓'; |
| color: var(--accent-color); |
| margin-right: 0.5rem; |
| font-size: 1.4rem; |
| } |
| |
| .feature-list ul { |
| list-style: none; |
| padding-left: 1.5rem; |
| margin: 0.5rem 0 1rem; |
| } |
| |
| .feature-list ul li { |
| position: relative; |
| padding-left: 1.5rem; |
| margin: 0.5rem 0; |
| transition: var(--transition); |
| } |
| |
| .feature-list ul li:hover { |
| color: var(--primary-hover); |
| transform: translateX(5px); |
| } |
| |
| .feature-list ul li::before { |
| content: '•'; |
| position: absolute; |
| left: 0; |
| color: var(--accent-color); |
| font-size: 1.2rem; |
| } |
| |
| .feature-list ul ul { |
| border-left: 2px dashed var(--border-color); |
| margin-left: 0.5rem; |
| padding-left: 1rem; |
| } |
| |
| .feature-list ul ul li::before { |
| content: '◦'; |
| } |
| |
| |
| .toggle-button { |
| background: var(--primary-color); |
| color: white; |
| border: none; |
| border-radius: 50px; |
| padding: 0.5rem 1rem; |
| cursor: pointer; |
| font-family: 'Yomogi', cursive; |
| font-size: 0.9rem; |
| margin: 0.5rem 0; |
| transition: var(--transition); |
| display: inline-flex; |
| align-items: center; |
| box-shadow: var(--shadow); |
| } |
| |
| .toggle-button:hover { |
| background: var(--primary-hover); |
| transform: translateY(-2px); |
| } |
| |
| .toggle-button::after { |
| content: '↓'; |
| margin-left: 0.5rem; |
| transition: var(--transition); |
| } |
| |
| .toggle-button[aria-expanded="true"]::after { |
| transform: rotate(180deg); |
| } |
| |
| |
| .expandable-content { |
| overflow: hidden; |
| max-height: 0; |
| opacity: 0; |
| transition: max-height 0.5s ease, opacity 0.3s ease; |
| } |
| |
| .expandable-content.show { |
| max-height: 2000px; |
| opacity: 1; |
| } |
| |
| |
| section#video { |
| text-align: center; |
| padding: 3rem 1rem; |
| } |
| |
| section#video h2 { |
| font-size: 2.2rem; |
| margin-bottom: 1.5rem; |
| color: var(--primary-color); |
| } |
| |
| iframe { |
| border-radius: 12px; |
| box-shadow: var(--shadow); |
| transition: var(--transition); |
| } |
| |
| iframe:hover { |
| transform: scale(1.02); |
| box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); |
| } |
| |
| |
| @keyframes fadeIn { |
| from { opacity: 0; } |
| to { opacity: 1; } |
| } |
| |
| @keyframes fadeInUp { |
| from { |
| opacity: 0; |
| transform: translateY(20px); |
| } |
| to { |
| opacity: 1; |
| transform: translateY(0); |
| } |
| } |
| |
| |
| @media (max-width: 768px) { |
| h1 { |
| font-size: 2.2rem; |
| } |
| |
| .buttons { |
| flex-direction: column; |
| align-items: center; |
| } |
| |
| .buttons a { |
| width: 100%; |
| text-align: center; |
| } |
| |
| iframe { |
| width: 100%; |
| height: auto; |
| aspect-ratio: 16/9; |
| } |
| |
| .header-content { |
| padding: 1rem; |
| } |
| } |
| .scrollbar { |
| -ms-overflow-style: none; |
| scrollbar-width: none; |
| } |
| |
| .scrollbar::-webkit-scrollbar { |
| display: none; |
| } |
| |
| </style> |
| </head> |
|
|
| <body> |
| |
| <div class="scroll-progress" id="scrollProgress"></div> |
|
|
| |
| <div class="loading-overlay" id="loadingOverlay"> |
| <div class="loader"></div> |
| </div> |
|
|
| |
| <noscript> |
| <iframe src="https://www.googletagmanager.com/ns.html?id=GTM-PJXRKX3F" height="0" width="0" style="display:none;visibility:hidden"> |
| </iframe> |
| </noscript> |
| |
| |
| |
| <div class="header-container"> |
| <video autoplay muted loop class="header-video"> |
| <source src="https://huggingface.co/datasets/soiz1/scratch-for-school/resolve/main/vi.mp4?download=true" type="video/mp4"> |
| |
| Your browser does not support the video tag. |
| </video> |
| <div class="header-content"> |
| <h1>Scratch for school</h1> |
| <p class="description">学校の一人一台端末用にカスタマイズされたScratch。Googleドライブへの保存機能やプロジェクトの共有、カスタマイズされた便利なエディターや高度なブロック、画像分類やフェイストラッキング、ハンドトラッキング、ポーズ認識の拡張機能などの様々な機能があります。</p> |
| <div class="buttons"> |
| <a href="https://soiz1-s4s-editor.hf.space/editor.html" target="_blank">→エディターを開く</a> |
| <a href="#features">→機能一覧</a> |
| <a href="#video">→紹介動画</a> |
| </div> |
| </div> |
| </div> |
| |
| <script src="https://unpkg.com/alpinejs@3.14.9/dist/cdn.min.js" defer></script> |
| <section id="features"> |
| <h2>機能一覧</h2> |
| |
| <div class="feature-list"> |
| <li>プロジェクトの保存・共有</li> |
| <ul> |
| <li>プロジェクトをGoogleドライブに保存</li> |
| <li>特定の人とだけの共有</li> |
| <li>プロジェクトの短縮URLの作成</li> |
| <li>プラットフォームへの共有</li> |
| </ul> |
| </div> |
| |
| <div class="feature-list"> |
| <li>カスタマイズされたエディター</li> |
| <ul> |
| <li>オフスクリーンレンダリングによる高速化</li> |
| <li>フォルダにプロジェクトを保存</li> |
| <li>フォルダをZIPとして読み込む</li> |
| <li>ライトテーマとダークテーマ</li> |
| <li>デバイスのフォントの使用とカスタムフォントを使用した文字の作成</li> |
| <li>文字の位置を設定</li> |
| <li>新しい背景とコスチュームとサウンド</li> |
| <li>背景、コスチューム、サウンドの検索</li> |
| <li>カラーピッカーの透明度の設定</li> |
| <li>変数とリストを分離</li> |
| <li>拡張機能の検索とカテゴリー別のフィルター</li> |
| <li>値を返したり色をカスタマイズしたりできるブロック定義</li> |
| <li>部位同士の重なった部分の抽出・削除</li> |
| <li>100個を超える新しいブロック</li> |
| <li>高度な設定</li> |
| <ul> |
| <li>ステージのサイズを変更</li> |
| <li>FPS設定</li> |
| <li>ペンできれいに描画する</li> |
| <li>ワープタイマー</li> |
| <li>クローン、動く範囲と大きさなどの制限を解除</li> |
| <li>オフスクリーンレンダリングの有効・無効化</li> |
| </ul> |
| </ul> |
| </div> |
| |
| <div class="feature-list"> |
| <li>100個を超える拡張機能</li> |
| <ul> |
| <li>独自の拡張機能の読み込み</li> |
| <li>画像内のオブジェクトの認識</li> |
| <li>ハンドトラッキング</li> |
| <li>フェイストラッキング</li> |
| <li>高精度な画像認識AIを作成</li> |
| <li>プロジェクト内で画像認識AIの学習と認識</li> |
| <li>ポーズ認識</li> |
| <li>p5.jsによるアートノイズ生成</li> |
| <li>ステージ内のカメラ移動</li> |
| <li>ファイルのアップロード</li> |
| <li>ZIPを編集</li> |
| <li>高度なペン</li> |
| |
| <li> |
| <button class="toggle-button" aria-expanded="false" aria-controls="moreExtensions">もっと見る</button> |
| <div id="moreExtensions" class="expandable-content"> |
| <ul> |
| <li>音声のグループ化</li> |
| <li>複雑なオーディオ操作とエフェクト</li> |
| <li>音の作成</li> |
| <li>動き、イベント、制御、演算カテゴリーの拡張</li> |
| <li>更に高度な定義ブロック</li> |
| <li>コメントの拡張</li> |
| <li>JSON配列の制御</li> |
| <li>Swift JSONの制御</li> |
| <li>パーティクルの作成</li> |
| <li>変数のスタイルの変更</li> |
| <li>物理演算の簡易化</li> |
| <li>スムーズなアニメーション</li> |
| <li>追従と整列</li> |
| <li>スプライトをグリッド上に配置</li> |
| <li>ステージ全体への視覚効果</li> |
| <li>クローンブロックの拡張</li> |
| <li>スプライトを他の画像として表示</li> |
| <li>個別のタイマー</li> |
| <li>ブロックスタック内のみの変数</li> |
| <li>ランタイムまたはスレッド内のみの変数</li> |
| <li>スクラッチオブジェクトの編集</li> |
| <li>フォントの管理</li> |
| <li>プロジェクトを閉ても維持するストレージ</li> |
| <li>HTTPリクエスト</li> |
| <li>WebSocket</li> |
| <li>コンパイルされたスクリプトを並列で実行</li> |
| <li>Penguinmod API</li> |
| <li>三次元用に拡張された演算</li> |
| <li>乱数の拡張</li> |
| <li>文字の圧縮と解凍</li> |
| <li>便利なブロック</li> |
| <li>ログの記録と変数</li> |
| <li>Iframeの作成</li> |
| <li>カラーピッカーの表示</li> |
| <li>色の計算</li> |
| <li>ブロックのすべてのメニューを抽出</li> |
| <li>コメント</li> |
| <li>パーリンノイズ</li> |
| <li>ゲームパッド</li> |
| <li>印刷</li> |
| <li>ステージの切り抜き</li> |
| <li>マウスカーソルの固定</li> |
| <li>カーソルの見た目の変更</li> |
| <li>Scratch認証</li> |
| <li>Javascriptを実行</li> |
| <li>配列</li> |
| <li>スプライトとクローンへの直接アクセス</li> |
| <li>非常に大きな数の計算</li> |
| <li>色のユーティリティ</li> |
| </ul> |
| </div> |
| </li> |
| |
| <li>拡張機能エディター</li> |
| </ul> |
| </div> |
| |
| <div class="feature-list"> |
| <li>60個を超えるSharkpoolの拡張機能</li> |
| <ul> |
| <li>更に拡張された定義ブロック</li> |
| <li>0znzwに触発させて特定のスクリプトの実行</li> |
| <li>「見た目」カテゴリーの拡張</li> |
| <li>ポップアップの表示</li> |
| <li>様々なユーリティ</li> |
| <li>時差の計算ブロック</li> |
| |
| <li> |
| <button class="toggle-button" aria-expanded="false" aria-controls="moreSharkpool">もっと見る</button> |
| <div id="moreSharkpool" class="expandable-content"> |
| <ul> |
| <li>Scratchの統計</li> |
| <li>ランダムシード番号や地形の生成</li> |
| <li>複雑なオーディオ操作とエフェクト</li> |
| <li>新しい動きブロック</li> |
| <li>YoutubeAPI</li> |
| <li>GeometryDashAPI</li> |
| <li>オシレーターの演奏</li> |
| <li>「調べる」カテゴリーの拡張</li> |
| <li>高度なキー検出</li> |
| <li>ビデオセンシング拡張機能の拡張</li> |
| <li>クローン無しでパーティクルを作成</li> |
| <li>SVG、スプライト、ステージにエフェクトを適用</li> |
| <li>画像にエフェクトやフィルターを適用</li> |
| <li>画像のピクセルデータの作成と編集</li> |
| <li>ピクセルユーティリティ</li> |
| <li>マイクの録音</li> |
| <li>Newgroundsから音声を取得</li> |
| <li>スプライトをリンクさせて親の動きに追従</li> |
| <li>衝突検出</li> |
| <li>ボックスの衝突検出</li> |
| <li>ファイル拡張機能の拡張</li> |
| <li>スプライト、スレッド、プロジェクト用の一時変数</li> |
| <li>新しい変数モニター</li> |
| <li>リストのカスタマイズ</li> |
| <li>ゲームパッド拡張機能の拡張</li> |
| <li>タイルグリッド上にスプライトを配置</li> |
| <li>「2000年以降」ブロックの拡張</li> |
| <li>アニメーションキーフレームの作成</li> |
| <li>プロジェクト、スクリプト、スプライトを一時停止</li> |
| <li>TikTokAPIの音声読み上げ</li> |
| <li>メッセージブロック</li> |
| <li>高度なメッセージブロック</li> |
| <li>高度なFetch</li> |
| <li>ユーザーの現在位置の取得</li> |
| <li>Spotifyの音楽を再生</li> |
| <li>SoundCloudAPI</li> |
| <li>Googleスプレッドシートの読み書き</li> |
| <li>通貨情報</li> |
| <li>高度なテキストの表示</li> |
| <li>色のユーティリティーと変換</li> |
| <li>QRコードの作成と読み取り</li> |
| <li>実行時にイベントを検出</li> |
| <li>カスタマイズ可能な吹き出し</li> |
| <li>プロジェクトのフォント管理</li> |
| <li>レイヤーの操作</li> |
| <li>ペン、背景、ビデオカメラ、スプライトなどのビジュアル</li> |
| <li>タイムゾーン変換</li> |
| <li>パーリンノイズ</li> |
| <li>高度な制御ブロック</li> |
| <li>新しい強力な演算</li> |
| <li>クライアントベースのキャプチャ</li> |
| <li>コメントのカスタマイズ</li> |
| <li>スプライトとクローンの管理</li> |
| <li>DOMの取得</li> |
| <li>SVGスプライトの作成とエクスポート</li> |
| <li>プロジェクトの宣伝</li> |
| <li>GIFの作成と分割</li> |
| <li>超高速JSON配列</li> |
| <li>カスタムドロップダウンの作成</li> |
| <li>スキン拡張機能の改良</li> |
| <li>Unityのようなシーンを作成</li> |
| <li>ペンレイヤーの作成</li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| |
| <div class="feature-list"> |
| <li>40個を超えるPenguinmodの拡張機能</li> |
| <ul> |
| <li>WebSocket</li> |
| <li>Pen+</li> |
| <li>物理処理</li> |
| <li>高速なJSON処理</li> |
| <li>ファイルの更新(直接編集)</li> |
| <li>3D数学</li> |
| <li>スコープ変数</li> |
| <li>音声を文字起こし</li> |
| <li>背景除去</li> |
| <li>エンドツーエンド暗号化</li> |
| <li>WebRTC</li> |
| <li>ランダムユーティリティ</li> |
| <li>ユーザーの位置情報</li> |
| <li>値の型を追加</li> |
| <li>PenguinAI(chatGPTやDALL E3など)</li> |
| <li>スプライトシート</li> |
| <li>webhook</li> |
| <li>アラート</li> |
| <li>数値ユーティリティ</li> |
| <li>高度な数学</li> |
| <li>小数点以下の拡張による高精度演算</li> |
| <li>GithubAPI</li> |
| <li>Google認証</li> |
| <li>PenguinmodAPI</li> |
| <li>Discord</li> |
| <li>Twitch</li> |
| <li>チェス</li> |
| <li>天気予報</li> |
| <li>CORS PROXY Fetch</li> |
| <li>生の拡張機能へのアクセス</li> |
| <li>プロジェクトページの操作(一部はs4sで使用できない)</li> |
| <li>すべてのメニュー</li> |
| <li>フィールド</li> |
| <li>Beepbox</li> |
| <li>ファイルをネットに保存</li> |
| <li>URLの#以降の取得</li> |
| <li>Scratchブロックの生成</li> |
| <li>猫に関するブロック</li> |
| <li>Scratchで削除されたカウンターブロック</li> |
| <li>文字から行数を取得</li> |
| <li>Wssサーバー</li> |
| <li>TTStool APIによる読み上げ</li> |
| <li>画面やカメラを共有</li> |
| <li>エディターでマウスについてくる猫</li> |
| <li>Web GPU</li> |
| <li>数値の書式</li> |
| <li>プロジェクトにインターフェースを追加</li> |
| <li>ブロックAI</li> |
| </ul> |
| </div> |
| |
| <div class="feature-list"> |
| <li>90個を超えるTurbowarpの拡張機能</li> |
| </div> |
| </section> |
| |
| <section id="video"> |
| <h2>紹介動画</h2> |
| <iframe width="560" height="315" src="https://www.youtube.com/embed/" title="解説動画" frameborder="0" allowfullscreen></iframe> |
| </section> |
| |
| <script> |
| |
| window.addEventListener('load', function() { |
| setTimeout(function() { |
| document.getElementById('loadingOverlay').classList.add('hidden'); |
| }, 800); |
| }); |
| |
| |
| document.addEventListener('DOMContentLoaded', function() { |
| const toggleButtons = document.querySelectorAll('.toggle-button'); |
| |
| toggleButtons.forEach(button => { |
| button.addEventListener('click', function() { |
| const expanded = this.getAttribute('aria-expanded') === 'true'; |
| const targetId = this.getAttribute('aria-controls'); |
| const target = document.getElementById(targetId); |
| |
| this.setAttribute('aria-expanded', !expanded); |
| |
| if (!expanded) { |
| target.classList.add('show'); |
| } else { |
| target.classList.remove('show'); |
| } |
| }); |
| }); |
| }); |
| |
| |
| document.addEventListener('click', function(e) { |
| if (e.target.classList.contains('buttons') || e.target.closest('.buttons a')) { |
| return; |
| } |
| |
| const buttons = document.querySelectorAll('.buttons a'); |
| buttons.forEach(button => { |
| button.addEventListener('click', function(e) { |
| e.preventDefault(); |
| const href = this.getAttribute('href'); |
| |
| |
| const ripple = document.createElement('span'); |
| ripple.classList.add('ripple'); |
| this.appendChild(ripple); |
| |
| |
| setTimeout(() => { |
| if (href.startsWith('http')) { |
| window.open(href, '_blank'); |
| } else { |
| document.querySelector(href).scrollIntoView({ |
| behavior: 'smooth' |
| }); |
| } |
| ripple.remove(); |
| }, 300); |
| }); |
| }); |
| }); |
| |
| |
| window.addEventListener('scroll', function() { |
| const scrollProgress = document.getElementById('scrollProgress'); |
| const scrollTop = window.pageYOffset || document.documentElement.scrollTop; |
| const scrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight; |
| const scrollPercentage = (scrollTop / scrollHeight) * 100; |
| |
| scrollProgress.style.width = scrollPercentage + '%'; |
| scrollProgress.style.background = 'var(--primary-color)'; |
| }); |
| |
| |
| const sections = document.querySelectorAll('section'); |
| |
| function checkScroll() { |
| sections.forEach(section => { |
| const sectionTop = section.getBoundingClientRect().top; |
| const windowHeight = window.innerHeight; |
| |
| if (sectionTop < windowHeight * 0.75) { |
| section.classList.add('visible'); |
| } |
| }); |
| } |
| |
| window.addEventListener('scroll', checkScroll); |
| window.addEventListener('load', checkScroll); |
| </script> |
| </body> |
|
|
| </html> |