[{"data":1,"prerenderedAt":685},["ShallowReactive",2],{"article-flow-field-art":3},{"id":4,"title":5,"body":6,"date":677,"description":678,"extension":679,"meta":680,"navigation":166,"path":681,"seo":682,"stem":683,"__hash__":684},"articles\u002Farticles\u002Fflow-field-art.md","パーティクルフローフィールド — 粒子と力場のシミュレーション",{"type":7,"value":8,"toc":668},"minimark",[9,13,17,20,23,26,29,32,43,45,48,55,295,298,300,303,314,433,440,442,446,458,461,508,511,518,520,523,530,577,580,582,585,654,664],[10,11,12],"h2",{"id":12},"作品",[14,15,16],"p",{},"380 個の粒子が、sin \u002F cos を重ね合わせた「ベクトル場」の流れに沿ってキャンバス上を漂います。\n粒子の軌跡は半透明の暗いオーバーレイで徐々に消え、絶えず変化する模様を作り出します。",[18,19],"flow-field",{},[14,21,22],{},"クリック \u002F タップするとフィールドの時間軸がジャンプし、風向きが急変します。",[24,25],"hr",{},[10,27,28],{"id":28},"フローフィールドとは",[14,30,31],{},"フローフィールド（Flow Field）は平面上のすべての点に「向き（角度）」を持ったベクトルを定義したものです。\n粒子はそのベクトルに従って進み、多数の軌跡が重なることで複雑な模様が生まれます。",[33,34,39],"pre",{"className":35,"code":37,"language":38},[36],"language-text"," ↗ → ↘ ↓ ↙ ← ↖    ← 各格子点にベクトルが定義されている\n ↑ ↗ → ↘ ↓ ↙ ←\n ↖ ↑ ↗ → ↘ ↓ ↙\n","text",[40,41,37],"code",{"__ignoreMap":42},"",[24,44],{},[10,46,47],{"id":47},"ベクトル場の定義",[14,49,50,51,54],{},"このアートでは sin \u002F cos の重ね合わせで角度を決める数式を使っています。\n時間 ",[40,52,53],{},"t"," を変数に含めることで、フィールドが時間とともに変化し続けます。",[33,56,60],{"className":57,"code":58,"language":59,"meta":42,"style":42},"language-ts shiki shiki-themes github-light github-dark","function fieldAngle(x: number, y: number, t: number): number {\n  const nx = x \u002F SIZE  \u002F\u002F 0〜1 に正規化\n  const ny = y \u002F SIZE\n\n  return (\n    Math.sin(nx * 4.5 + t * 0.35) * Math.cos(ny * 3.2 + t * 0.22) +\n    Math.cos(nx * 2.1 - ny * 1.8 + t * 0.14)\n  ) * Math.PI\n}\n","ts",[40,61,62,118,143,161,168,177,239,276,289],{"__ignoreMap":42},[63,64,67,71,75,79,83,86,90,93,96,98,100,102,104,106,108,111,113,115],"span",{"class":65,"line":66},"line",1,[63,68,70],{"class":69},"szBVR","function",[63,72,74],{"class":73},"sScJk"," fieldAngle",[63,76,78],{"class":77},"sVt8B","(",[63,80,82],{"class":81},"s4XuR","x",[63,84,85],{"class":69},":",[63,87,89],{"class":88},"sj4cs"," number",[63,91,92],{"class":77},", ",[63,94,95],{"class":81},"y",[63,97,85],{"class":69},[63,99,89],{"class":88},[63,101,92],{"class":77},[63,103,53],{"class":81},[63,105,85],{"class":69},[63,107,89],{"class":88},[63,109,110],{"class":77},")",[63,112,85],{"class":69},[63,114,89],{"class":88},[63,116,117],{"class":77}," {\n",[63,119,121,124,127,130,133,136,139],{"class":65,"line":120},2,[63,122,123],{"class":69},"  const",[63,125,126],{"class":88}," nx",[63,128,129],{"class":69}," =",[63,131,132],{"class":77}," x ",[63,134,135],{"class":69},"\u002F",[63,137,138],{"class":88}," SIZE",[63,140,142],{"class":141},"sJ8bj","  \u002F\u002F 0〜1 に正規化\n",[63,144,146,148,151,153,156,158],{"class":65,"line":145},3,[63,147,123],{"class":69},[63,149,150],{"class":88}," ny",[63,152,129],{"class":69},[63,154,155],{"class":77}," y ",[63,157,135],{"class":69},[63,159,160],{"class":88}," SIZE\n",[63,162,164],{"class":65,"line":163},4,[63,165,167],{"emptyLinePlaceholder":166},true,"\n",[63,169,171,174],{"class":65,"line":170},5,[63,172,173],{"class":69},"  return",[63,175,176],{"class":77}," (\n",[63,178,180,183,186,189,192,195,198,201,203,206,209,211,214,217,220,222,225,227,229,231,234,236],{"class":65,"line":179},6,[63,181,182],{"class":77},"    Math.",[63,184,185],{"class":73},"sin",[63,187,188],{"class":77},"(nx ",[63,190,191],{"class":69},"*",[63,193,194],{"class":88}," 4.5",[63,196,197],{"class":69}," +",[63,199,200],{"class":77}," t ",[63,202,191],{"class":69},[63,204,205],{"class":88}," 0.35",[63,207,208],{"class":77},") ",[63,210,191],{"class":69},[63,212,213],{"class":77}," Math.",[63,215,216],{"class":73},"cos",[63,218,219],{"class":77},"(ny ",[63,221,191],{"class":69},[63,223,224],{"class":88}," 3.2",[63,226,197],{"class":69},[63,228,200],{"class":77},[63,230,191],{"class":69},[63,232,233],{"class":88}," 0.22",[63,235,208],{"class":77},[63,237,238],{"class":69},"+\n",[63,240,242,244,246,248,250,253,256,259,261,264,266,268,270,273],{"class":65,"line":241},7,[63,243,182],{"class":77},[63,245,216],{"class":73},[63,247,188],{"class":77},[63,249,191],{"class":69},[63,251,252],{"class":88}," 2.1",[63,254,255],{"class":69}," -",[63,257,258],{"class":77}," ny ",[63,260,191],{"class":69},[63,262,263],{"class":88}," 1.8",[63,265,197],{"class":69},[63,267,200],{"class":77},[63,269,191],{"class":69},[63,271,272],{"class":88}," 0.14",[63,274,275],{"class":77},")\n",[63,277,279,282,284,286],{"class":65,"line":278},8,[63,280,281],{"class":77},"  ) ",[63,283,191],{"class":69},[63,285,213],{"class":77},[63,287,288],{"class":88},"PI\n",[63,290,292],{"class":65,"line":291},9,[63,293,294],{"class":77},"}\n",[14,296,297],{},"各係数を変えると模様が変わります。係数の比が整数に近いほど規則的な渦が生まれ、\n無理数比に近いほど複雑でカオス的なパターンになります。",[24,299],{},[10,301,302],{"id":302},"パーティクルの移動",[14,304,305,306,309,310,313],{},"粒子は毎フレーム、自分の現在地から ",[40,307,308],{},"fieldAngle"," を求めて速度を更新します。\n速度をいきなり変えず ",[40,311,312],{},"0.88"," の慣性係数を掛けることで、動きが滑らかになります。",[33,315,317],{"className":57,"code":316,"language":59,"meta":42,"style":42},"const angle = fieldAngle(p.x, p.y, t)\n\n\u002F\u002F 慣性あり：急に向きが変わらず、流れるような動きになる\np.vx = p.vx * 0.88 + Math.cos(angle) * speed * 0.12\np.vy = p.vy * 0.88 + Math.sin(angle) * speed * 0.12\n\np.x += p.vx\np.y += p.vy\n",[40,318,319,334,338,343,378,408,412,423],{"__ignoreMap":42},[63,320,321,324,327,329,331],{"class":65,"line":66},[63,322,323],{"class":69},"const",[63,325,326],{"class":88}," angle",[63,328,129],{"class":69},[63,330,74],{"class":73},[63,332,333],{"class":77},"(p.x, p.y, t)\n",[63,335,336],{"class":65,"line":120},[63,337,167],{"emptyLinePlaceholder":166},[63,339,340],{"class":65,"line":145},[63,341,342],{"class":141},"\u002F\u002F 慣性あり：急に向きが変わらず、流れるような動きになる\n",[63,344,345,348,351,354,356,359,361,363,365,368,370,373,375],{"class":65,"line":163},[63,346,347],{"class":77},"p.vx ",[63,349,350],{"class":69},"=",[63,352,353],{"class":77}," p.vx ",[63,355,191],{"class":69},[63,357,358],{"class":88}," 0.88",[63,360,197],{"class":69},[63,362,213],{"class":77},[63,364,216],{"class":73},[63,366,367],{"class":77},"(angle) ",[63,369,191],{"class":69},[63,371,372],{"class":77}," speed ",[63,374,191],{"class":69},[63,376,377],{"class":88}," 0.12\n",[63,379,380,383,385,388,390,392,394,396,398,400,402,404,406],{"class":65,"line":170},[63,381,382],{"class":77},"p.vy ",[63,384,350],{"class":69},[63,386,387],{"class":77}," p.vy ",[63,389,191],{"class":69},[63,391,358],{"class":88},[63,393,197],{"class":69},[63,395,213],{"class":77},[63,397,185],{"class":73},[63,399,367],{"class":77},[63,401,191],{"class":69},[63,403,372],{"class":77},[63,405,191],{"class":69},[63,407,377],{"class":88},[63,409,410],{"class":65,"line":179},[63,411,167],{"emptyLinePlaceholder":166},[63,413,414,417,420],{"class":65,"line":241},[63,415,416],{"class":77},"p.x ",[63,418,419],{"class":69},"+=",[63,421,422],{"class":77}," p.vx\n",[63,424,425,428,430],{"class":65,"line":278},[63,426,427],{"class":77},"p.y ",[63,429,419],{"class":69},[63,431,432],{"class":77}," p.vy\n",[14,434,435,436,439],{},"画面外に出るか寿命（",[40,437,438],{},"life","）が尽きた粒子は、ランダムな位置で新生します。",[24,441],{},[10,443,445],{"id":444},"残像トレイル効果","残像（トレイル）効果",[14,447,448,449,452,453,457],{},"スピログラフではキャンバスを ",[40,450,451],{},"clearRect"," で完全に消去してから描き直していました。\nフローフィールドでは",[454,455,456],"strong",{},"消去しない","ことが重要です。",[14,459,460],{},"代わりに毎フレームの最初に「極めて薄い暗い矩形」を重ねます。",[33,462,464],{"className":57,"code":463,"language":59,"meta":42,"style":42},"ctx.fillStyle = 'rgba(13, 17, 23, 0.06)'  \u002F\u002F 不透明度 6% の暗いオーバーレイ\nctx.fillRect(0, 0, SIZE, SIZE)\n",[40,465,466,480],{"__ignoreMap":42},[63,467,468,471,473,477],{"class":65,"line":66},[63,469,470],{"class":77},"ctx.fillStyle ",[63,472,350],{"class":69},[63,474,476],{"class":475},"sZZnC"," 'rgba(13, 17, 23, 0.06)'",[63,478,479],{"class":141},"  \u002F\u002F 不透明度 6% の暗いオーバーレイ\n",[63,481,482,485,488,490,493,495,497,499,502,504,506],{"class":65,"line":120},[63,483,484],{"class":77},"ctx.",[63,486,487],{"class":73},"fillRect",[63,489,78],{"class":77},[63,491,492],{"class":88},"0",[63,494,92],{"class":77},[63,496,492],{"class":88},[63,498,92],{"class":77},[63,500,501],{"class":88},"SIZE",[63,503,92],{"class":77},[63,505,501],{"class":88},[63,507,275],{"class":77},[14,509,510],{},"これにより古い軌跡は 1 フレームごとに 6% ずつ暗くなり、約 16 フレームで消えます。\n結果として「長い尾を引きながら流れる」ように見えます。",[512,513,515],"callout",{"type":514},"tip",[14,516,517],{},"オーバーレイの不透明度が高いほど尾が短くなり、低いほど長く残ります。0.01〜0.15 の範囲で試すと印象が大きく変わります。",[24,519],{},[10,521,522],{"id":522},"クリックで風向きを変える",[14,524,525,526,529],{},"クリック時は ",[40,527,528],{},"tOffset"," を大きくジャンプさせることで、\nフィールドの時間軸を飛ばして「急な風向き変化」を表現しています。",[33,531,533],{"className":57,"code":532,"language":59,"meta":42,"style":42},"function shiftField() {\n  tOffset += 4 + Math.random() * 3  \u002F\u002F 4〜7 秒分ジャンプ\n}\n",[40,534,535,545,573],{"__ignoreMap":42},[63,536,537,539,542],{"class":65,"line":66},[63,538,70],{"class":69},[63,540,541],{"class":73}," shiftField",[63,543,544],{"class":77},"() {\n",[63,546,547,550,552,555,557,559,562,565,567,570],{"class":65,"line":120},[63,548,549],{"class":77},"  tOffset ",[63,551,419],{"class":69},[63,553,554],{"class":88}," 4",[63,556,197],{"class":69},[63,558,213],{"class":77},[63,560,561],{"class":73},"random",[63,563,564],{"class":77},"() ",[63,566,191],{"class":69},[63,568,569],{"class":88}," 3",[63,571,572],{"class":141},"  \u002F\u002F 4〜7 秒分ジャンプ\n",[63,574,575],{"class":65,"line":145},[63,576,294],{"class":77},[14,578,579],{},"滑らかに変化するフィールドの流れが突然乱れ、\n渦や吹き返しが生まれる瞬間を楽しめます。",[24,581],{},[10,583,584],{"id":584},"手法まとめ",[586,587,588,604],"table",{},[589,590,591],"thead",{},[592,593,594,598,601],"tr",{},[595,596,597],"th",{},"技術",[595,599,600],{},"性質",[595,602,603],{},"本作での役割",[605,606,607,621,632,643],"tbody",{},[592,608,609,615,618],{},[610,611,612],"td",{},[40,613,614],{},"requestAnimationFrame",[610,616,617],{},"60fps ループ",[610,619,620],{},"フレームごとに粒子を更新",[592,622,623,626,629],{},[610,624,625],{},"sin \u002F cos 合成",[610,627,628],{},"連続・周期的",[610,630,631],{},"時間変化するベクトル場",[592,633,634,637,640],{},[610,635,636],{},"半透明オーバーレイ",[610,638,639],{},"積算描画",[610,641,642],{},"残像・トレイル効果",[592,644,645,648,651],{},[610,646,647],{},"慣性係数",[610,649,650],{},"低域フィルタ",[610,652,653],{},"動きの滑らかさ",[512,655,657],{"type":656},"warning",[14,658,659,660,663],{},"粒子数を増やすと描画コストが上がります。モバイルでは ",[40,661,662],{},"COUNT"," を 200 程度に下げるとフレームレートが安定します。",[665,666,667],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":42,"searchDepth":120,"depth":120,"links":669},[670,671,672,673,674,675,676],{"id":12,"depth":120,"text":12},{"id":28,"depth":120,"text":28},{"id":47,"depth":120,"text":47},{"id":302,"depth":120,"text":302},{"id":444,"depth":120,"text":445},{"id":522,"depth":120,"text":522},{"id":584,"depth":120,"text":584},"2026-05-01T22:00:00+09:00","数百の粒子が時間変化するベクトル場に沿って流れる Canvas シミュレーションアートです。クリックで風向きを変えられます。","md",{},"\u002Farticles\u002Fflow-field-art",{"title":5,"description":678},"articles\u002Fflow-field-art","lzWzpTbeBkkA_PiHq0VObsuF1ygo1ze9JzFA18Oovfs",1777568741983]