<html style="max-height: 100%;"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><style id="basic-style"></style><style id="root-style">:root{--pic-image-data:none;}</style><style id="out-style">:root {
--bg-color: #1a2035;
--dot-color: #FFD700;
--dot-size: 8px;
--grid-gap: 10px;
--anim-duration: 1.2s;
}
body {
margin: 0;
padding: 0;
background-color: var(--bg-color);
color: var(--dot-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
font-family: 'Courier New', Courier, monospace;
overflow: hidden;
}
.loader-container {
position: relative;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
transform-origin: center center;
transition: transform 1.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.dot {
position: absolute;
left: 50%;
top: 50%;
width: var(--dot-size);
height: var(--dot-size);
transform: translate3d(var(--tx), var(--ty), 0);
transition: transform var(--anim-duration) cubic-bezier(0.4, 0.0, 0.2, 1), opacity var(--anim-duration) ease;
will-change: transform, opacity;
}
.dot-inner {
display: block;
width: 100%;
height: 100%;
background-color: var(--dot-color);
border-radius: 50%;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}</style><style id="pic-style">html { max-height: 100%; }</style><style id="vsc-protection">body { pointer-events: auto !important; opacity: 1 !important; }.vsc-controller { display: none !important; }</style></head><body id="svg-section" style="width: 856px; height: 482px; transform-origin: left top; transform: scale(1); overflow: auto; margin: 0; padding: 0;" data-vsc-ignore="true" class="vsc-ignore"><div class="loader-container" id="container" aria-live="polite" aria-label="Loading animation">
</div>
<div class="sr-only" id="aria-status">Loading</div>
<script id="js-section">class DotTextLoader {
constructor(containerId, options = {}) {
this.container = document.getElementById(containerId);
this.gridGap = options.gridGap || 10;
this.fontSize = options.fontSize || 150;
this.fontFamily = options.fontFamily || 'Verdana, sans-serif';
if (options.dotSize) {
document.documentElement.style.setProperty('--dot-size', options.dotSize + 'px');
}
this.baseWidth = 1920;
this.baseHeight = 1080;
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d', { willReadFrequently: true });
// ドットを格納するラッパー要素を作成(スケーリング用)
this.stage = document.createElement('div');
this.stage.style.position = 'absolute';
this.stage.style.top = '50%';
this.stage.style.left = '50%';
this.stage.style.width = this.baseWidth + 'px';
this.stage.style.height = this.baseHeight + 'px';
this.stage.style.marginLeft = -(this.baseWidth / 2) + 'px';
this.stage.style.marginTop = -(this.baseHeight / 2) + 'px';
this.stage.style.transformOrigin = 'center center';
this.container.appendChild(this.stage);
this.dots = [];
this.textCoords = [];
this.emojiCoords = [];
this.isAnimating = false;
}
// スケール更新(画面リサイズ時に呼ばれる)
updateScale() {
const scaleW = window.innerWidth / this.baseWidth;
const scaleH = window.innerHeight / this.baseHeight;
// アスペクト比を維持しつつ、画面に収まるようにスケール(contain)
const scale = Math.min(scaleW, scaleH);
this.stage.style.transform = `scale(${scale})`;
}
calculateTextCoordinates(text) {
const width = this.baseWidth;
const height = this.baseHeight;
this.canvas.width = width;
this.canvas.height = height;
this.ctx.clearRect(0, 0, width, height);
this.ctx.font = `bold ${this.fontSize}px ${this.fontFamily}`;
this.ctx.textAlign = 'center';
this.ctx.textBaseline = 'middle';
this.ctx.fillStyle = '#fff';
this.ctx.fillText(text, width / 2, height / 2);
return this.scanCanvas();
}
calculateEmojiCoordinates() {
const width = this.canvas.width;
const height = this.canvas.height;
const ctx = this.ctx;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = '#fff';
// thinking2.svg のSVGパスデータ
const paths = [
"M195.522003,544.373779 C186.149826,518.729004 179.770172,492.799805 177.609894,465.906067 C172.333755,400.222595 186.057404,338.801331 219.435867,281.970276 C243.655533,240.733170 276.701538,207.758972 316.150452,181.060318 C361.038971,150.680191 410.459167,132.078308 464.105286,124.552849 C494.256378,120.323257 524.378601,119.897484 554.673828,123.483849 C625.094482,131.820282 687.756775,158.497559 741.986328,203.849472 C793.515869,246.943375 827.324341,301.619141 842.762268,367.231140 C849.114929,394.230133 852.018188,421.684357 851.142883,449.425171 C849.580139,498.953644 838.151062,546.039551 814.194885,589.601196 C794.289185,625.797363 768.040710,656.638000 734.769531,681.537903 C702.629272,705.591614 667.398865,723.139709 628.879822,734.040527 C607.709351,740.031738 586.126892,744.187866 564.075134,745.371521 C558.801758,745.654602 554.835693,747.263000 550.834351,751.517883 C545.740173,756.934692 543.670410,760.464050 546.893433,768.451843 C553.316284,784.369812 544.952026,800.784851 527.878296,810.369934 C509.059692,820.934570 488.519501,826.634705 467.643524,831.024109 C450.233215,834.684814 432.760345,838.359924 414.972321,839.763550 C375.963562,842.841614 338.755493,837.980469 306.167023,813.946960 C286.171143,799.200378 272.026154,779.994202 263.341644,756.775818 C251.447708,724.977112 247.748337,692.587952 256.712738,659.353882 C256.842804,658.871765 256.864258,658.322998 257.116028,657.916626 C262.564240,649.122925 258.505188,643.198303 252.256363,636.440430 C227.456635,609.620605 208.708160,578.892151 195.522003,544.373779 M231.376282,304.790527 C166.789841,426.920135 205.621521,558.759705 273.161530,626.923523 C285.256256,612.668152 299.445984,600.485901 312.390808,587.073059 C318.671997,580.564697 324.253845,573.535339 327.895996,565.176575 C334.724121,549.506104 334.085510,533.434387 330.327087,517.201294 C326.308228,499.843170 333.335968,485.186188 348.830811,478.455322 C365.269897,471.314362 387.369354,475.631104 399.688934,488.656982 C421.392609,511.604980 427.148834,539.514343 424.700409,569.949524 C424.158691,576.683472 421.722748,583.067261 420.883118,590.059570 C422.829010,589.692383 424.307617,589.474976 425.756165,589.130859 C459.572815,581.097717 493.365356,572.961670 527.206360,565.032410 C558.937744,557.597473 590.368896,548.816833 622.706604,544.084595 C638.073364,541.835815 650.768066,545.290466 659.557739,558.982361 C663.879395,565.714111 666.505737,573.062500 667.039856,580.970276 C668.151978,597.433594 662.382446,614.759094 643.776184,622.195374 C626.433655,629.126526 608.660522,634.637085 590.611816,639.346985 C578.770508,642.437012 566.960327,645.646240 554.837585,648.881714 C555.378906,649.945679 555.582275,650.575500 555.965271,651.064819 C567.655823,665.998718 567.078369,690.021423 552.920532,703.146973 C550.748352,705.160583 551.000305,707.117249 552.673096,709.278992 C555.468689,712.891846 557.397949,716.957031 558.210388,721.447632 C558.621277,723.718201 559.526367,724.559326 561.887817,724.261230 C567.335266,723.573547 572.849915,723.353027 578.266541,722.495972 C635.692749,713.409241 686.912781,690.698975 731.184448,652.727844 C764.656189,624.019714 790.211182,589.431458 807.219666,548.811584 C824.943726,506.482788 831.430786,462.302429 827.981506,416.454620 C825.101135,378.167786 814.668762,342.161499 797.264404,308.179169 C775.234070,265.164368 744.418030,229.580078 704.909851,201.609634 C660.209534,169.963348 610.564697,151.282043 556.206482,145.221680 C521.260437,141.325577 486.317322,142.055161 451.766602,148.615891 C384.328583,161.421448 325.626099,191.006363 277.684448,240.876190 C259.418915,259.876343 244.224243,281.001312 231.376282,304.790527 M410.516418,818.777771 C412.667389,818.570618 414.827362,818.431030 416.967957,818.146057 C439.088928,815.201233 460.932190,810.763062 482.570557,805.389587 C495.359100,802.213806 507.806946,797.903320 519.059692,790.796509 C525.013611,787.036438 527.407410,781.482239 526.148010,775.032593 C524.719543,767.717468 521.032043,763.941467 513.773865,762.527283 C511.325684,762.050354 508.841187,761.717346 506.358093,761.472778 C503.109528,761.152954 498.540039,761.878174 498.260620,757.635071 C497.985504,753.456909 502.744171,753.535156 505.792999,752.671570 C513.649536,750.446106 521.499512,748.284912 528.505554,743.840637 C534.259827,740.190491 536.957275,734.993408 536.571228,728.290771 C536.149170,720.961060 532.704773,715.760376 525.534729,713.202942 C520.290527,711.332336 514.911987,710.509644 509.393280,710.295288 C506.248138,710.173157 502.083038,710.546326 501.661285,706.609253 C501.229462,702.578613 505.532623,702.344177 508.482391,701.541870 C516.676941,699.313171 524.898193,697.189575 532.408752,693.033020 C536.818298,690.592773 540.013245,687.149780 541.595276,682.303284 C545.675476,669.803650 538.770935,658.362793 525.087830,655.512024 C516.269470,653.674683 507.213959,653.996887 498.266907,653.319275 C495.024689,653.073730 490.514709,653.337158 489.940216,649.491089 C489.332550,645.422791 494.055481,645.340393 496.829712,644.554260 C528.840942,635.483215 560.919250,626.648804 592.931702,617.581970 C607.648865,613.413818 622.613220,610.011414 636.650513,603.644287 C643.439392,600.564880 646.844910,595.319458 647.571960,588.160034 C648.117798,582.784668 647.375977,577.500427 645.471619,572.447998 C642.426697,564.369873 639.377136,562.484192 630.684082,563.081482 C628.029480,563.263855 625.359863,563.411255 622.735474,563.820679 C598.386169,567.618835 574.578003,573.937378 550.633423,579.575684 C502.237335,590.971924 453.923706,602.718201 405.569031,614.290771 C398.784637,615.914490 392.073334,618.176575 385.035736,618.230469 C378.288910,618.282166 374.895752,612.800659 377.676483,607.048706 C378.775421,604.775574 380.702301,603.569397 382.801331,602.513550 C391.089020,598.344482 396.812256,591.810303 399.932739,583.172241 C409.273956,557.314026 405.456360,532.809509 390.325775,510.458771 C383.701263,500.673126 374.147430,493.499054 360.785583,495.230072 C352.486359,496.305206 347.868774,502.757416 349.726044,510.890625 C350.280823,513.320129 351.162170,515.681396 351.622345,518.125122 C357.487854,549.272766 353.702301,577.785950 329.120880,600.668518 C320.099762,609.066101 311.076385,617.472961 302.349579,626.172058 C292.230377,636.259033 284.027191,647.652649 279.221924,661.351562 C271.348297,683.797668 271.685638,706.385498 277.463715,729.126282 C283.889771,754.417114 295.361816,776.729065 315.856537,793.682007 C343.279236,816.365662 375.137909,822.436951 410.516418,818.777771 z",
"M637.025635,428.372406 C620.258179,432.213226 606.000610,425.806213 594.924500,409.722534 C580.361206,388.575012 580.747986,353.056946 595.788940,332.291199 C597.041504,330.561859 598.429565,328.930695 600.114990,326.797852 C596.063538,326.298706 593.078979,328.269379 589.861206,329.040222 C587.597656,329.582428 585.347229,330.179199 583.086487,330.733246 C573.779968,333.014038 566.822571,329.169586 563.997864,320.193207 C561.044556,310.808044 564.397400,303.645569 573.504333,300.226227 C592.016052,293.275513 611.205627,289.964050 630.919373,288.535095 C662.709900,286.230865 693.206970,291.425079 722.935059,302.351593 C727.800232,304.139771 732.390808,306.472626 736.963379,308.858551 C746.005737,313.576935 748.328735,320.119263 744.395691,329.608643 C741.065369,337.643860 732.745605,341.402527 724.127258,338.121826 C715.264282,334.747986 706.514160,331.128296 697.320740,328.679749 C682.332825,324.687775 667.145203,322.115692 651.566101,321.592102 C651.100708,323.226776 652.547302,323.661621 653.248047,324.302704 C674.783997,344.005554 678.586670,384.217865 661.560669,410.051422 C655.719543,418.914062 648.008118,425.563324 637.025635,428.372406 z",
"M419.021423,296.782349 C430.104767,302.752869 437.301025,311.627930 441.513092,322.950836 C450.143707,346.151703 449.213593,368.727692 435.826263,389.939240 C418.684143,417.100067 384.545837,416.908844 367.808289,389.455139 C353.642761,366.220123 352.790833,341.760925 364.784882,317.516724 C372.549988,301.820709 385.554657,292.618195 403.844360,292.736145 C409.065765,292.769775 414.020264,294.234009 419.021423,296.782349 z",
"M444.892639,267.203918 C406.926514,254.930191 369.268036,255.098785 331.538422,266.392242 C330.262421,266.774170 328.974213,267.115112 327.695404,267.487854 C313.805267,271.536438 303.453857,262.490814 305.814911,248.242935 C306.608551,243.453644 309.491028,240.344345 314.111176,238.485718 C331.873749,231.339996 350.408997,227.421631 369.368500,225.834213 C397.178070,223.505814 424.544159,226.314682 451.208008,234.841644 C460.091949,237.682678 468.802307,241.000107 477.075958,245.357117 C485.086090,249.575348 487.277832,256.327698 483.574341,265.205109 C480.280548,273.100403 472.251068,277.119873 464.444519,274.468750 C457.988800,272.276398 451.661926,269.704651 444.892639,267.203918 z",
"M601.175659,513.541626 C601.423645,524.756592 595.645508,531.166992 586.580200,530.323364 C583.792419,530.063904 581.546387,528.646729 579.303528,527.245117 C558.400269,514.182312 535.762817,505.808990 511.337280,502.574951 C492.197113,500.040710 473.157593,500.645325 454.398254,505.779053 C450.566833,506.827576 446.823425,508.335144 442.752075,508.367462 C435.713562,508.423309 431.339325,504.996033 429.910156,498.253235 C428.525879,491.722076 431.041443,487.800934 437.786102,484.795959 C459.148102,475.278412 481.742798,474.625275 504.425934,475.973969 C526.296265,477.274384 547.561157,482.007141 567.847534,490.554260 C577.695251,494.703308 587.126465,499.609222 595.609619,506.210571 C598.033386,508.096680 600.098267,510.167816 601.175659,513.541626 z"
];
const cx = width / 2;
const cy = height / 2;
const svgW = 1024;
const svgH = 1024;
// 絵文字を2回り小さくする(0.85 → 0.45)
const targetH = Math.max(height * 0.45, 200);
const scale = targetH / svgH;
ctx.save();
ctx.translate(cx, cy);
ctx.scale(scale, scale);
ctx.translate(-svgW / 2, -svgH / 2);
ctx.fillStyle = '#fff';
paths.forEach((d, index) => {
ctx.save();
// 顔と手の隙間調整
if (index === 3) {
ctx.translate(0, -12);
}
// 目を上向きに(目のパスを上に移動して「考えている」表情に)
if (index === 1 || index === 2) {
ctx.translate(0, -25);
}
const p = new Path2D(d);
ctx.fill(p);
ctx.restore();
});
ctx.restore();
return this.scanCanvas();
}
scanCanvas() {
const width = this.canvas.width;
const height = this.canvas.height;
const coordinates = [];
const imageData = this.ctx.getImageData(0, 0, width, height).data;
const gap = this.gridGap;
for (let y = 0; y < height; y += gap) {
for (let x = 0; x < width; x += gap) {
const index = (y * width + x) * 4;
const alpha = imageData[index + 3];
if (alpha > 128) {
coordinates.push({ x: x - width / 2, y: y - height / 2 });
}
}
}
return coordinates;
}
initDots(text) {
this.textCoords = this.calculateTextCoordinates(text);
this.emojiCoords = this.calculateEmojiCoordinates();
const maxCount = Math.max(this.textCoords.length, this.emojiCoords.length);
const fragment = document.createDocumentFragment();
this.dots = [];
for (let i = 0; i < maxCount; i++) {
const textCoord = this.textCoords[i] || this.textCoords[this.textCoords.length - 1];
const emojiCoord = this.emojiCoords[i] || this.emojiCoords[this.emojiCoords.length - 1];
const dotElement = document.createElement('div');
dotElement.className = 'dot active';
dotElement.innerHTML = '<span class="dot-inner"></span>';
dotElement.style.setProperty('--tx', `${textCoord.x}px`);
dotElement.style.setProperty('--ty', `${textCoord.y}px`);
dotElement.dataset.textX = textCoord.x;
dotElement.dataset.textY = textCoord.y;
dotElement.dataset.emojiX = emojiCoord.x;
dotElement.dataset.emojiY = emojiCoord.y;
this.dots.push(dotElement);
this.stage.appendChild(dotElement);
}
this.updateScale();
}
formEmoji() {
this.dots.forEach((dot) => {
// ランダムな遅延を加えることで、「固まって動く」のではなく「バラバラと変形する」表現にする
const delay = Math.random() * 0.6;
dot.style.transitionDelay = `${delay}s`;
const targetX = parseFloat(dot.dataset.emojiX);
const targetY = parseFloat(dot.dataset.emojiY);
dot.style.setProperty('--tx', `${targetX}px`);
dot.style.setProperty('--ty', `${targetY}px`);
dot.classList.remove('active');
});
}
formText() {
this.dots.forEach((dot) => {
// 戻る時も同様にバラバラと戻る
const delay = Math.random() * 0.6;
dot.style.transitionDelay = `${delay}s`;
const textX = parseFloat(dot.dataset.textX);
const textY = parseFloat(dot.dataset.textY);
dot.style.setProperty('--tx', `${textX}px`);
dot.style.setProperty('--ty', `${textY}px`);
dot.classList.add('active');
});
}
clearDots() {
this.stage.innerHTML = '';
this.dots = [];
}
}
document.addEventListener('DOMContentLoaded', () => {
// 読み込み完了後にサイズ調整が確実に行われるようにする
window.addEventListener('resize', loader => {
// loaderがスコープ外なのでここでの実装は注意が必要。
// DotTextLoader内でresizeをlistenする方がクリーンだが、
// 今回は既存のコード構造を維持して下に修正を入れる。
});
// オプション指定を削除し、クラス内のデフォルト設定(gridGap, fontSize)を使用するように変更
const loader = new DotTextLoader('container');
loader.initDots("LOADING");
let isTextState = true;
const morphLoop = () => {
if (isTextState) {
loader.formEmoji();
isTextState = false;
setTimeout(morphLoop, 3000);
} else {
loader.formText();
isTextState = true;
setTimeout(morphLoop, 3000);
}
};
setTimeout(morphLoop, 2000);
// リサイズ時のちらつき(ドット再生成)を防ぎ、スケール調整のみにする
let timeoutId;
window.addEventListener('resize', () => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
loader.updateScale();
}, 100);
});
});</script></body></html>