summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyuilo <4439005+syuilo@users.noreply.github.com>2025-10-24 10:41:55 +0900
committersyuilo <4439005+syuilo@users.noreply.github.com>2025-10-24 10:41:55 +0900
commit2d1b7c957adcfe2e0d0c34f570e424a7d20a8787 (patch)
tree538528e6ea38cb05d15bf8d79b49fdd1c107114b
parentUpdate about-misskey.vue (diff)
parentBump version to 2025.10.1-beta.3 (diff)
downloadmisskey-2d1b7c957adcfe2e0d0c34f570e424a7d20a8787.tar.gz
misskey-2d1b7c957adcfe2e0d0c34f570e424a7d20a8787.tar.bz2
misskey-2d1b7c957adcfe2e0d0c34f570e424a7d20a8787.zip
Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop
-rw-r--r--CHANGELOG.md1
-rw-r--r--package.json2
-rw-r--r--packages/frontend-shared/js/emojilist.ts11
-rw-r--r--packages/frontend/src/components/MkAnimBg.fragment.glsl111
-rw-r--r--packages/frontend/src/components/MkAnimBg.vertex.glsl15
-rw-r--r--packages/frontend/src/components/MkAnimBg.vue123
-rw-r--r--packages/frontend/src/components/MkReactionsViewer.reaction.vue6
-rw-r--r--packages/frontend/src/components/MkSuperMenu.vue4
-rw-r--r--packages/frontend/src/composables/use-uploader.ts4
-rw-r--r--packages/frontend/src/directives/appear.ts3
-rw-r--r--packages/frontend/src/directives/tooltip.ts5
-rw-r--r--packages/frontend/src/directives/user-preview.ts2
-rw-r--r--packages/frontend/src/type.ts8
-rw-r--r--packages/frontend/src/types/misc.ts6
-rw-r--r--packages/frontend/src/utility/snowfall-effect.fragment.glsl23
-rw-r--r--packages/frontend/src/utility/snowfall-effect.ts57
-rw-r--r--packages/frontend/src/utility/snowfall-effect.vertex.glsl37
-rw-r--r--packages/misskey-js/package.json2
18 files changed, 226 insertions, 194 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e0957a145..f503759432 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@
- ウォーターマークを回転させた際に画面からはみ出た部分を考慮できるように
- Fix: 投票が終了した後に投票結果が正しく表示されない問題を修正
- Fix: ダークモードの同期が機能しない場合がある問題を修正
+- Fix: iOSで動画の圧縮を行うと音声トラックが失われる問題を修正
### Server
- Enhance: 管理者/モデレーターはファイルのアップロード制限をバイパスするように
diff --git a/package.json b/package.json
index abc399593c..251df75971 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "misskey",
- "version": "2025.10.1-beta.2",
+ "version": "2025.10.1-beta.3",
"codename": "nasubi",
"repository": {
"type": "git",
diff --git a/packages/frontend-shared/js/emojilist.ts b/packages/frontend-shared/js/emojilist.ts
index 09bea06719..20ddd0f7d7 100644
--- a/packages/frontend-shared/js/emojilist.ts
+++ b/packages/frontend-shared/js/emojilist.ts
@@ -39,13 +39,18 @@ for (let i = 0; i < emojilist.length; i++) {
export const emojiCharByCategory = _charGroupByCategory;
-export function getUnicodeEmoji(char: string): UnicodeEmojiDef | string {
+export function getUnicodeEmojiOrNull(char: string): UnicodeEmojiDef | null {
// Colorize it because emojilist.json assumes that
return unicodeEmojisMap.get(colorizeEmoji(char))
// カラースタイル絵文字がjsonに無い場合はテキストスタイル絵文字にフォールバックする
?? unicodeEmojisMap.get(char)
- // それでも見つからない場合はそのまま返す(絵文字情報がjsonに無い場合、このフォールバックが無いとレンダリングに失敗する)
- ?? char;
+ // それでも見つからない場合はnullを返す
+ ?? null;
+}
+
+export function getUnicodeEmoji(char: string): UnicodeEmojiDef | string {
+ // 絵文字が見つからない場合はそのまま返す(絵文字情報がjsonに無い場合、このフォールバックが無いとレンダリングに失敗する)
+ return getUnicodeEmojiOrNull(char) ?? char;
}
export function isSupportedEmoji(char: string): boolean {
diff --git a/packages/frontend/src/components/MkAnimBg.fragment.glsl b/packages/frontend/src/components/MkAnimBg.fragment.glsl
new file mode 100644
index 0000000000..d40872bb7a
--- /dev/null
+++ b/packages/frontend/src/components/MkAnimBg.fragment.glsl
@@ -0,0 +1,111 @@
+#version 300 es
+precision mediump float;
+
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+vec3 mod289(vec3 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec2 mod289(vec2 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec3 permute(vec3 x) {
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+float snoise(vec2 v) {
+ const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439);
+
+ vec2 i = floor(v + dot(v, C.yy));
+ vec2 x0 = v - i + dot(i, C.xx);
+
+ vec2 i1;
+ i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
+ vec4 x12 = x0.xyxy + C.xxzz;
+ x12.xy -= i1;
+
+ i = mod289(i);
+ vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));
+
+ vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0);
+ m = m*m;
+ m = m*m;
+
+ vec3 x = 2.0 * fract(p * C.www) - 1.0;
+ vec3 h = abs(x) - 0.5;
+ vec3 ox = floor(x + 0.5);
+ vec3 a0 = x - ox;
+
+ m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);
+
+ vec3 g;
+ g.x = a0.x * x0.x + h.x * x0.y;
+ g.yz = a0.yz * x12.xz + h.yz * x12.yw;
+ return 130.0 * dot(m, g);
+}
+
+in vec2 in_uv;
+uniform float u_time;
+uniform vec2 u_resolution;
+uniform float u_spread;
+uniform float u_speed;
+uniform float u_warp;
+uniform float u_focus;
+uniform float u_itensity;
+out vec4 out_color;
+
+float circle(in vec2 _pos, in vec2 _origin, in float _radius) {
+ float SPREAD = 0.7 * u_spread;
+ float SPEED = 0.00055 * u_speed;
+ float WARP = 1.5 * u_warp;
+ float FOCUS = 1.15 * u_focus;
+
+ vec2 dist = _pos - _origin;
+
+ float distortion = snoise(vec2(
+ _pos.x * 1.587 * WARP + u_time * SPEED * 0.5,
+ _pos.y * 1.192 * WARP + u_time * SPEED * 0.3
+ )) * 0.5 + 0.5;
+
+ float feather = 0.01 + SPREAD * pow(distortion, FOCUS);
+
+ return 1.0 - smoothstep(
+ _radius - (_radius * feather),
+ _radius + (_radius * feather),
+ dot( dist, dist ) * 4.0
+ );
+}
+
+void main() {
+ vec3 green = vec3(1.0) - vec3(153.0 / 255.0, 211.0 / 255.0, 221.0 / 255.0);
+ vec3 purple = vec3(1.0) - vec3(195.0 / 255.0, 165.0 / 255.0, 242.0 / 255.0);
+ vec3 orange = vec3(1.0) - vec3(255.0 / 255.0, 156.0 / 255.0, 136.0 / 255.0);
+
+ float ratio = u_resolution.x / u_resolution.y;
+
+ vec2 uv = vec2(in_uv.x, in_uv.y / ratio) * 0.5 + 0.5;
+
+ vec3 color = vec3(0.0);
+
+ float greenMix = snoise(in_uv * 1.31 + u_time * 0.8 * 0.00017) * 0.5 + 0.5;
+ float purpleMix = snoise(in_uv * 1.26 + u_time * 0.8 * -0.0001) * 0.5 + 0.5;
+ float orangeMix = snoise(in_uv * 1.34 + u_time * 0.8 * 0.00015) * 0.5 + 0.5;
+
+ float alphaOne = 0.35 + 0.65 * pow(snoise(vec2(u_time * 0.00012, uv.x)) * 0.5 + 0.5, 1.2);
+ float alphaTwo = 0.35 + 0.65 * pow(snoise(vec2((u_time + 1561.0) * 0.00014, uv.x )) * 0.5 + 0.5, 1.2);
+ float alphaThree = 0.35 + 0.65 * pow(snoise(vec2((u_time + 3917.0) * 0.00013, uv.x )) * 0.5 + 0.5, 1.2);
+
+ color += vec3(circle(uv, vec2(0.22 + sin(u_time * 0.000201) * 0.06, 0.80 + cos(u_time * 0.000151) * 0.06), 0.15)) * alphaOne * (purple * purpleMix + orange * orangeMix);
+ color += vec3(circle(uv, vec2(0.90 + cos(u_time * 0.000166) * 0.06, 0.42 + sin(u_time * 0.000138) * 0.06), 0.18)) * alphaTwo * (green * greenMix + purple * purpleMix);
+ color += vec3(circle(uv, vec2(0.19 + sin(u_time * 0.000112) * 0.06, 0.25 + sin(u_time * 0.000192) * 0.06), 0.09)) * alphaThree * (orange * orangeMix);
+
+ color *= u_itensity + 1.0 * pow(snoise(vec2(in_uv.y + u_time * 0.00013, in_uv.x + u_time * -0.00009)) * 0.5 + 0.5, 2.0);
+
+ vec3 inverted = vec3(1.0) - color;
+ out_color = vec4(color, max(max(color.x, color.y), color.z));
+}
diff --git a/packages/frontend/src/components/MkAnimBg.vertex.glsl b/packages/frontend/src/components/MkAnimBg.vertex.glsl
new file mode 100644
index 0000000000..56d6b017b1
--- /dev/null
+++ b/packages/frontend/src/components/MkAnimBg.vertex.glsl
@@ -0,0 +1,15 @@
+#version 300 es
+
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+in vec2 position;
+uniform vec2 u_scale;
+out vec2 in_uv;
+
+void main() {
+ gl_Position = vec4(position, 0.0, 1.0);
+ in_uv = position / u_scale;
+}
diff --git a/packages/frontend/src/components/MkAnimBg.vue b/packages/frontend/src/components/MkAnimBg.vue
index 0e1018dcbf..bcdc604bb8 100644
--- a/packages/frontend/src/components/MkAnimBg.vue
+++ b/packages/frontend/src/components/MkAnimBg.vue
@@ -10,6 +10,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted, onUnmounted, useTemplateRef } from 'vue';
import isChromatic from 'chromatic/isChromatic';
+import vertexShaderSource from './MkAnimBg.vertex.glsl';
+import fragmentShaderSource from './MkAnimBg.fragment.glsl';
import { initShaderProgram } from '@/utility/webgl.js';
const canvasEl = useTemplateRef('canvasEl');
@@ -42,126 +44,7 @@ onMounted(() => {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
- const shaderProgram = initShaderProgram(gl, `#version 300 es
- in vec2 position;
- uniform vec2 u_scale;
- out vec2 in_uv;
-
- void main() {
- gl_Position = vec4(position, 0.0, 1.0);
- in_uv = position / u_scale;
- }
- `, `#version 300 es
- precision mediump float;
-
- vec3 mod289(vec3 x) {
- return x - floor(x * (1.0 / 289.0)) * 289.0;
- }
-
- vec2 mod289(vec2 x) {
- return x - floor(x * (1.0 / 289.0)) * 289.0;
- }
-
- vec3 permute(vec3 x) {
- return mod289(((x*34.0)+1.0)*x);
- }
-
- float snoise(vec2 v) {
- const vec4 C = vec4(0.211324865405187,
- 0.366025403784439,
- -0.577350269189626,
- 0.024390243902439);
-
- vec2 i = floor(v + dot(v, C.yy) );
- vec2 x0 = v - i + dot(i, C.xx);
-
- vec2 i1;
- i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
- vec4 x12 = x0.xyxy + C.xxzz;
- x12.xy -= i1;
-
- i = mod289(i);
- vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
- + i.x + vec3(0.0, i1.x, 1.0 ));
-
- vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
- m = m*m ;
- m = m*m ;
-
- vec3 x = 2.0 * fract(p * C.www) - 1.0;
- vec3 h = abs(x) - 0.5;
- vec3 ox = floor(x + 0.5);
- vec3 a0 = x - ox;
-
- m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
-
- vec3 g;
- g.x = a0.x * x0.x + h.x * x0.y;
- g.yz = a0.yz * x12.xz + h.yz * x12.yw;
- return 130.0 * dot(m, g);
- }
-
- in vec2 in_uv;
- uniform float u_time;
- uniform vec2 u_resolution;
- uniform float u_spread;
- uniform float u_speed;
- uniform float u_warp;
- uniform float u_focus;
- uniform float u_itensity;
- out vec4 out_color;
-
- float circle( in vec2 _pos, in vec2 _origin, in float _radius ) {
- float SPREAD = 0.7 * u_spread;
- float SPEED = 0.00055 * u_speed;
- float WARP = 1.5 * u_warp;
- float FOCUS = 1.15 * u_focus;
-
- vec2 dist = _pos - _origin;
-
- float distortion = snoise( vec2(
- _pos.x * 1.587 * WARP + u_time * SPEED * 0.5,
- _pos.y * 1.192 * WARP + u_time * SPEED * 0.3
- ) ) * 0.5 + 0.5;
-
- float feather = 0.01 + SPREAD * pow( distortion, FOCUS );
-
- return 1.0 - smoothstep(
- _radius - ( _radius * feather ),
- _radius + ( _radius * feather ),
- dot( dist, dist ) * 4.0
- );
- }
-
- void main() {
- vec3 green = vec3( 1.0 ) - vec3( 153.0 / 255.0, 211.0 / 255.0, 221.0 / 255.0 );
- vec3 purple = vec3( 1.0 ) - vec3( 195.0 / 255.0, 165.0 / 255.0, 242.0 / 255.0 );
- vec3 orange = vec3( 1.0 ) - vec3( 255.0 / 255.0, 156.0 / 255.0, 136.0 / 255.0 );
-
- float ratio = u_resolution.x / u_resolution.y;
-
- vec2 uv = vec2( in_uv.x, in_uv.y / ratio ) * 0.5 + 0.5;
-
- vec3 color = vec3( 0.0 );
-
- float greenMix = snoise( in_uv * 1.31 + u_time * 0.8 * 0.00017 ) * 0.5 + 0.5;
- float purpleMix = snoise( in_uv * 1.26 + u_time * 0.8 * -0.0001 ) * 0.5 + 0.5;
- float orangeMix = snoise( in_uv * 1.34 + u_time * 0.8 * 0.00015 ) * 0.5 + 0.5;
-
- float alphaOne = 0.35 + 0.65 * pow( snoise( vec2( u_time * 0.00012, uv.x ) ) * 0.5 + 0.5, 1.2 );
- float alphaTwo = 0.35 + 0.65 * pow( snoise( vec2( ( u_time + 1561.0 ) * 0.00014, uv.x ) ) * 0.5 + 0.5, 1.2 );
- float alphaThree = 0.35 + 0.65 * pow( snoise( vec2( ( u_time + 3917.0 ) * 0.00013, uv.x ) ) * 0.5 + 0.5, 1.2 );
-
- color += vec3( circle( uv, vec2( 0.22 + sin( u_time * 0.000201 ) * 0.06, 0.80 + cos( u_time * 0.000151 ) * 0.06 ), 0.15 ) ) * alphaOne * ( purple * purpleMix + orange * orangeMix );
- color += vec3( circle( uv, vec2( 0.90 + cos( u_time * 0.000166 ) * 0.06, 0.42 + sin( u_time * 0.000138 ) * 0.06 ), 0.18 ) ) * alphaTwo * ( green * greenMix + purple * purpleMix );
- color += vec3( circle( uv, vec2( 0.19 + sin( u_time * 0.000112 ) * 0.06, 0.25 + sin( u_time * 0.000192 ) * 0.06 ), 0.09 ) ) * alphaThree * ( orange * orangeMix );
-
- color *= u_itensity + 1.0 * pow( snoise( vec2( in_uv.y + u_time * 0.00013, in_uv.x + u_time * -0.00009 ) ) * 0.5 + 0.5, 2.0 );
-
- vec3 inverted = vec3( 1.0 ) - color;
- out_color = vec4(color, max(max(color.x, color.y), color.z));
- }
- `);
+ const shaderProgram = initShaderProgram(gl, vertexShaderSource, fragmentShaderSource);
if (shaderProgram == null) return;
gl.useProgram(shaderProgram);
diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue
index d96f0e2420..7c60288883 100644
--- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue
+++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue
@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, inject, onMounted, useTemplateRef, watch } from 'vue';
import * as Misskey from 'misskey-js';
-import { getUnicodeEmoji } from '@@/js/emojilist.js';
+import { getUnicodeEmojiOrNull } from '@@/js/emojilist.js';
import MkCustomEmojiDetailedDialog from './MkCustomEmojiDetailedDialog.vue';
import type { MenuItem } from '@/types/menu';
import XDetails from '@/components/MkReactionsViewer.details.vue';
@@ -60,11 +60,11 @@ const buttonEl = useTemplateRef('buttonEl');
const emojiName = computed(() => props.reaction.replace(/:/g, '').replace(/@\./, ''));
const canToggle = computed(() => {
- const emoji = customEmojisMap.get(emojiName.value) ?? getUnicodeEmoji(props.reaction);
+ const emoji = customEmojisMap.get(emojiName.value) ?? getUnicodeEmojiOrNull(props.reaction);
// TODO
//return !props.reaction.match(/@\w/) && $i && emoji && checkReactionPermissions($i, props.note, emoji);
- return !props.reaction.match(/@\w/) && $i && emoji;
+ return props.reaction.match(/@\w/) == null && $i != null && emoji != null;
});
const canGetInfo = computed(() => !props.reaction.match(/@\w/) && props.reaction.includes(':'));
const isLocalCustomEmoji = props.reaction[0] === ':' && props.reaction.includes('@.');
diff --git a/packages/frontend/src/components/MkSuperMenu.vue b/packages/frontend/src/components/MkSuperMenu.vue
index dbc673333c..236afa127c 100644
--- a/packages/frontend/src/components/MkSuperMenu.vue
+++ b/packages/frontend/src/components/MkSuperMenu.vue
@@ -64,6 +64,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts">
+import type { Awaitable } from '@/types/misc.js';
+
export type SuperMenuDef = {
title?: string;
items: ({
@@ -80,7 +82,7 @@ export type SuperMenuDef = {
text: string;
danger?: boolean;
active?: boolean;
- action: (ev: MouseEvent) => void | Promise<void>;
+ action: (ev: MouseEvent) => Awaitable<void>;
} | {
type?: 'link';
to: string;
diff --git a/packages/frontend/src/composables/use-uploader.ts b/packages/frontend/src/composables/use-uploader.ts
index 12b6e85940..e4aa1fda53 100644
--- a/packages/frontend/src/composables/use-uploader.ts
+++ b/packages/frontend/src/composables/use-uploader.ts
@@ -634,7 +634,9 @@ export function useUploader(options: {
bitrate: item.compressionLevel === 1 ? mediabunny.QUALITY_VERY_HIGH : item.compressionLevel === 2 ? mediabunny.QUALITY_MEDIUM : mediabunny.QUALITY_VERY_LOW,
},
audio: {
- bitrate: item.compressionLevel === 1 ? mediabunny.QUALITY_VERY_HIGH : item.compressionLevel === 2 ? mediabunny.QUALITY_MEDIUM : mediabunny.QUALITY_VERY_LOW,
+ // Explicitly keep audio (don't discard) and copy it if possible
+ // without re-encoding to avoid WebCodecs limitations on iOS Safari
+ discard: false,
},
});
diff --git a/packages/frontend/src/directives/appear.ts b/packages/frontend/src/directives/appear.ts
index f714871420..117dc397da 100644
--- a/packages/frontend/src/directives/appear.ts
+++ b/packages/frontend/src/directives/appear.ts
@@ -5,6 +5,7 @@
import { throttle } from 'throttle-debounce';
import type { Directive } from 'vue';
+import type { Awaitable } from '@/types/misc.js';
interface HTMLElementWithObserver extends HTMLElement {
_observer_?: IntersectionObserver;
@@ -31,4 +32,4 @@ export const appearDirective = {
unmounted(src) {
if (src._observer_) src._observer_.disconnect();
},
-} as Directive<HTMLElementWithObserver, () => void>;
+} as Directive<HTMLElementWithObserver, (() => Awaitable<void>) | null | undefined>;
diff --git a/packages/frontend/src/directives/tooltip.ts b/packages/frontend/src/directives/tooltip.ts
index 9cfa8d657d..8839d9a939 100644
--- a/packages/frontend/src/directives/tooltip.ts
+++ b/packages/frontend/src/directives/tooltip.ts
@@ -15,7 +15,7 @@ const start = isTouchUsing ? 'touchstart' : 'mouseenter';
const end = isTouchUsing ? 'touchend' : 'mouseleave';
type TooltipDirectiveState = {
- text: string;
+ text: string | null | undefined;
_close: null | (() => void);
showTimer: number | null;
hideTimer: number | null;
@@ -53,6 +53,7 @@ export const tooltipDirective = {
if (binding.arg === 'dialog') {
el.addEventListener('click', (ev) => {
+ if (binding.value == null) return;
ev.preventDefault();
ev.stopPropagation();
alert({
@@ -128,4 +129,4 @@ export const tooltipDirective = {
if (self.checkTimer) window.clearTimeout(self.checkTimer);
self.close();
},
-} as Directive<TooltipDirectiveElement, string, TooltipDirectiveModifiers, TooltipDirectiveArg>;
+} as Directive<TooltipDirectiveElement, string | null | undefined, TooltipDirectiveModifiers, TooltipDirectiveArg>;
diff --git a/packages/frontend/src/directives/user-preview.ts b/packages/frontend/src/directives/user-preview.ts
index 76e345a108..f81f5dbef8 100644
--- a/packages/frontend/src/directives/user-preview.ts
+++ b/packages/frontend/src/directives/user-preview.ts
@@ -131,4 +131,4 @@ export const userPreviewDirective = {
if (self == null) return;
self.preview.detach();
},
-} as Directive<UserPreviewDirectiveElement, string | Misskey.entities.UserDetailed>;
+} as Directive<UserPreviewDirectiveElement, string | Misskey.entities.UserDetailed | null | undefined>;
diff --git a/packages/frontend/src/type.ts b/packages/frontend/src/type.ts
deleted file mode 100644
index 5ff27158d2..0000000000
--- a/packages/frontend/src/type.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
-
-export type WithNonNullable<T, K extends keyof T> = T & { [P in K]-?: NonNullable<T[P]> };
diff --git a/packages/frontend/src/types/misc.ts b/packages/frontend/src/types/misc.ts
new file mode 100644
index 0000000000..3ddd732531
--- /dev/null
+++ b/packages/frontend/src/types/misc.ts
@@ -0,0 +1,6 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export type Awaitable <T> = T | Promise<T>;
diff --git a/packages/frontend/src/utility/snowfall-effect.fragment.glsl b/packages/frontend/src/utility/snowfall-effect.fragment.glsl
new file mode 100644
index 0000000000..560af039e8
--- /dev/null
+++ b/packages/frontend/src/utility/snowfall-effect.fragment.glsl
@@ -0,0 +1,23 @@
+#version 300 es
+precision mediump float;
+
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+in vec4 v_color;
+in float v_rotation;
+uniform sampler2D u_texture;
+out vec4 out_color;
+
+void main() {
+ vec2 rotated = vec2(
+ cos(v_rotation) * (gl_PointCoord.x - 0.5) + sin(v_rotation) * (gl_PointCoord.y - 0.5) + 0.5,
+ cos(v_rotation) * (gl_PointCoord.y - 0.5) - sin(v_rotation) * (gl_PointCoord.x - 0.5) + 0.5
+ );
+
+ vec4 snowflake = texture(u_texture, rotated);
+
+ out_color = vec4(snowflake.rgb * v_color.xyz, snowflake.a * v_color.a);
+}
diff --git a/packages/frontend/src/utility/snowfall-effect.ts b/packages/frontend/src/utility/snowfall-effect.ts
index 65398e6a43..cefa720ebf 100644
--- a/packages/frontend/src/utility/snowfall-effect.ts
+++ b/packages/frontend/src/utility/snowfall-effect.ts
@@ -3,59 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-export class SnowfallEffect {
- private VERTEX_SOURCE = `#version 300 es
- in vec4 a_position;
- in vec4 a_color;
- in vec3 a_rotation;
- in vec3 a_speed;
- in float a_size;
- out vec4 v_color;
- out float v_rotation;
- uniform float u_time;
- uniform mat4 u_projection;
- uniform vec3 u_worldSize;
- uniform float u_gravity;
- uniform float u_wind;
- uniform float u_spin_factor;
- uniform float u_turbulence;
-
- void main() {
- v_color = a_color;
- v_rotation = a_rotation.x + (u_time * u_spin_factor) * a_rotation.y;
-
- vec3 pos = a_position.xyz;
-
- pos.x = mod(pos.x + u_time + u_wind * a_speed.x, u_worldSize.x * 2.0) - u_worldSize.x;
- pos.y = mod(pos.y - u_time * a_speed.y * u_gravity, u_worldSize.y * 2.0) - u_worldSize.y;
-
- pos.x += sin(u_time * a_speed.z * u_turbulence) * a_rotation.z;
- pos.z += cos(u_time * a_speed.z * u_turbulence) * a_rotation.z;
-
- gl_Position = u_projection * vec4(pos.xyz, a_position.w);
- gl_PointSize = (a_size / gl_Position.w) * 100.0;
- }
- `;
+import vertexSource from './snowfall-effect.vertex.glsl';
+import fragmentSource from './snowfall-effect.fragment.glsl';
- private FRAGMENT_SOURCE = `#version 300 es
- precision mediump float;
-
- in vec4 v_color;
- in float v_rotation;
- uniform sampler2D u_texture;
- out vec4 out_color;
-
- void main() {
- vec2 rotated = vec2(
- cos(v_rotation) * (gl_PointCoord.x - 0.5) + sin(v_rotation) * (gl_PointCoord.y - 0.5) + 0.5,
- cos(v_rotation) * (gl_PointCoord.y - 0.5) - sin(v_rotation) * (gl_PointCoord.x - 0.5) + 0.5
- );
-
- vec4 snowflake = texture(u_texture, rotated);
-
- out_color = vec4(snowflake.rgb * v_color.xyz, snowflake.a * v_color.a);
- }
- `;
+export class SnowfallEffect {
+ private VERTEX_SOURCE = vertexSource;
+ private FRAGMENT_SOURCE = fragmentSource;
private gl: WebGLRenderingContext;
private program: WebGLProgram;
diff --git a/packages/frontend/src/utility/snowfall-effect.vertex.glsl b/packages/frontend/src/utility/snowfall-effect.vertex.glsl
new file mode 100644
index 0000000000..bfca1a76ee
--- /dev/null
+++ b/packages/frontend/src/utility/snowfall-effect.vertex.glsl
@@ -0,0 +1,37 @@
+#version 300 es
+
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+in vec4 a_position;
+in vec4 a_color;
+in vec3 a_rotation;
+in vec3 a_speed;
+in float a_size;
+out vec4 v_color;
+out float v_rotation;
+uniform float u_time;
+uniform mat4 u_projection;
+uniform vec3 u_worldSize;
+uniform float u_gravity;
+uniform float u_wind;
+uniform float u_spin_factor;
+uniform float u_turbulence;
+
+void main() {
+ v_color = a_color;
+ v_rotation = a_rotation.x + (u_time * u_spin_factor) * a_rotation.y;
+
+ vec3 pos = a_position.xyz;
+
+ pos.x = mod(pos.x + u_time + u_wind * a_speed.x, u_worldSize.x * 2.0) - u_worldSize.x;
+ pos.y = mod(pos.y - u_time * a_speed.y * u_gravity, u_worldSize.y * 2.0) - u_worldSize.y;
+
+ pos.x += sin(u_time * a_speed.z * u_turbulence) * a_rotation.z;
+ pos.z += cos(u_time * a_speed.z * u_turbulence) * a_rotation.z;
+
+ gl_Position = u_projection * vec4(pos.xyz, a_position.w);
+ gl_PointSize = (a_size / gl_Position.w) * 100.0;
+}
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 6f067fbbc7..6af1945a31 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
{
"type": "module",
"name": "misskey-js",
- "version": "2025.10.1-beta.2",
+ "version": "2025.10.1-beta.3",
"description": "Misskey SDK for JavaScript",
"license": "MIT",
"main": "./built/index.js",