WKWebViewでthree.jsを表示した時にglbのテクスチャが真っ黒になる問題

WKWebViewでthree.jsのコンテンツを表示している際に、Blenderで作ったglbを読み込むと、WKWebViewをリロードした時に画像のテクスチャが真っ黒になる症状が発生しました。

その対策のためにやったことがこれらです。

three.jsのキャッシュを無効に

THREE.Cache.enabled = false;

効果なし🥲

GLTFLoaderを使いまわさない

function loadModel(path) {
  const loader = new GLTFLoader(); // 毎回新規作成
  loader.load(path, (gltf) => {
    scene.add(gltf.scene);
  });
}

効果なし🥲

読み込むglbファイルのパスに?${timestamp}をつける

const timestamp = Date.now();
loader.load(`model.glb?ts=${timestamp}`, ...);

効果なし🥲

webViewを作る際に毎回新しいプロセスプールを作成

let config = WKWebViewConfiguration()
config.processPool = WKProcessPool()
let webView = WKWebView(frame: .zero, configuration: config)

効果なし🥲

glbではなくgltf + bin + pngでエクスポートしたものを読み込む

const timestamp = Date.now();
loader.load(`model.gltf?ts=${timestamp}`, ...); //読み込むのはgltfだけでOK

効果なし🥲

GLTF読み込み後、テクスチャに needsUpdate = true

gltf.scene.traverse((child) => {
  if (child.isMesh && child.material.map) {
    child.material.map.needsUpdate = true;
  }
});

効果なし🥲

手動でテクスチャを読み込んでマテリアルに割り当てる

const tex = textureLoader.load('model/texture.png?ts=' + Date.now());

gltf.scene.traverse((child) => {
  if (child.isMesh && child.material.map) {
    const originalMap = child.material.map;
    const newMap = tex.clone();
    newMap.offset.copy(originalMap.offset);
    newMap.repeat.copy(originalMap.repeat);
    newMap.rotation = originalMap.rotation;
    newMap.center.copy(originalMap.center);
    newMap.wrapS = originalMap.wrapS;
    newMap.wrapT = originalMap.wrapT;
    newMap.flipY = originalMap.flipY;
    newMap.encoding = THREE.sRGBEncoding;
    child.material.map = newMap;
    child.material.needsUpdate = true;
  }
});

検証中…

バネみたいな動きの式

自分の中で「魔法の式」と呼んでいる式です。以下のような動きが実現できます。マウスカーソルを枠内に入れてみてください。スライダーで動きの調整も可能です。

  • 加速力
  • 摩擦力
  • 速さ

この動きを実現しているのがこんな式です。

移動量 = (移動量 + (目的地 - 現在地) / 摩擦力) * 加速力
現在地 += 移動量 * 速さ

上記のサンプルではX軸とY軸でそれぞれ移動量を出しています。具体的にはこんな感じ。

//moveX, moveY: 移動量
//toX, toY: 目的地(今回はカーソルの位置)
//x, y: 現在地(赤い丸の位置)
//friction: 摩擦力
//accel: 加速力

moveX = (moveX + (toX - x) / friction) * accel;
moveY = (moveY + (toY - y) / friction) * accel;
x += moveX * speed;
y += moveY * speed;
ball.style.left = x + "px";
ball.style.top = y + "px";

ゲームなんかで使えそうですかね。

MQL5でPOSTする方法

string Post (const string text) {
   uchar char_array[];
   int copied = StringToCharArray(text, char_array);
   string headers;
   char result[];
   int res = WebRequest("POST", "送信先URL", NULL, NULL, 10000, char_array, ArraySize(char_array), result, headers);
   return CharArrayToString(result);
}

こんな感じ。引数はkey=valueの形でもvalueのみでもOKです。使う時はこんな感じ。

//戻り値見たいならこれ
string res = Post("内容");

//戻り値見なくていいならこれ
Post("内容");

私の場合サーバー側はPHPで処理しておりまして、valueのみを送信した時はこんな感じで受け取っています。

//送信データの末尾に特殊文字がついてくるのでtrim()しています
$data = trim(file_get_contents('php://input'));

個人的なPOSTの目的は、口座の状況を見るのにVPSを開くのがダルいので、MT5の情報をWebで確認するために残高や評価額をPOSTしてWebで推移を見れるようにしています。

FIREシミュレーションiOS版をリリースしました

iOSアプリの「FIREシミュレーション」をリリースしました。FIREシミュレーションは資産・収入・支出を用いてFIREが可能かどうかをシミュレーションすることができるアプリです。収入や支出は項目ごとに期間を設定することができるので、ライフステージごとに金額を変更して、より正確なシミュレーションすることが可能です。

FIREシミュレーション

CSSでいい感じの縁取りをする方法

まずはこちらのCSSを使用した縁取りの例をいくつか紹介します。

こんな感じになります。
あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。
色を変えることも可能です。
ロールオーバーも可能。

CSSはこんな感じです。

.fuchi-text {
	--fuchi-width: 2px;
	--fuchi-color: #000;
	color: #fff;
	text-shadow:
	calc(cos(2 * pi / 32 * 0) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 0) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 0) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 0) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 0) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 0) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 1) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 1) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 1) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 1) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 1) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 1) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 2) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 2) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 2) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 2) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 2) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 2) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 3) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 3) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 3) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 3) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 3) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 3) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 4) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 4) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 4) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 4) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 4) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 4) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 5) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 5) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 5) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 5) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 5) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 5) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 6) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 6) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 6) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 6) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 6) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 6) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 7) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 7) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 7) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 7) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 7) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 7) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 8) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 8) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 8) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 8) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 8) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 8) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 9) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 9) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 9) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 9) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 9) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 9) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 10) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 10) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 10) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 10) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 10) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 10) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 11) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 11) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 11) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 11) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 11) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 11) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 12) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 12) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 12) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 12) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 12) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 12) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 13) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 13) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 13) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 13) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 13) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 13) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 14) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 14) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 14) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 14) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 14) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 14) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 15) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 15) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 15) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 15) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 15) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 15) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 16) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 16) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 16) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 16) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 16) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 16) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 17) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 17) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 17) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 17) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 17) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 17) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 18) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 18) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 18) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 18) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 18) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 18) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 19) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 19) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 19) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 19) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 19) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 19) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 20) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 20) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 20) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 20) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 20) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 20) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 21) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 21) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 21) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 21) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 21) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 21) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 22) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 22) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 22) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 22) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 22) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 22) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 23) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 23) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 23) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 23) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 23) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 23) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 24) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 24) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 24) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 24) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 24) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 24) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 25) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 25) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 25) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 25) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 25) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 25) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 26) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 26) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 26) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 26) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 26) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 26) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 27) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 27) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 27) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 27) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 27) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 27) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 28) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 28) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 28) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 28) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 28) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 28) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 29) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 29) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 29) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 29) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 29) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 29) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 30) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 30) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 30) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 30) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 30) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 30) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 31) * var(--fuchi-width)) calc(sin(2 * pi / 32 * 31) * var(--fuchi-width)) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 31) * var(--fuchi-width) * 1 / 3) calc(sin(2 * pi / 32 * 31) * var(--fuchi-width) * 1 / 3) 0 var(--fuchi-color),
	calc(cos(2 * pi / 32 * 31) * var(--fuchi-width) * 2 / 3) calc(sin(2 * pi / 32 * 31) * var(--fuchi-width) * 2 / 3) 0 var(--fuchi-color);
}

HTMLはこれだけでOK。こうすると・・・。

<span class="fuchi-text">サンプルテキスト</span>

こうなります。↓

サンプルテキスト

縁の色や幅も変更可能です。例えばこうすると・・・。

<span class="fuchi-text" style="--fuchi-color:#f00;--fuchi-width:4px;">サンプルテキスト</span>

こうなります。↓

サンプルテキスト

簡単に何をやっているのか説明すると、text-shadowをぐるりと1周させているだけです。そして縁が太い場合にスカスカになることがあるので、念の為半径を3段階に分けてぐるりとさせています。

ある程度の太さの縁には対応できると思いますが、極端に太い縁や大きい文字の場合はちょっとおかしな表示になるかもしれません。

縁がおかしくなった例

ほどほどでご利用ください。