前書き
Misskey Playを作る時の参考にどうぞ。
- 公式ドキュメント
- 初めてPlayを作る人はこちらの解説が参考になります
- 細かい困り事やAiScript全般のことはこちらの記事をどうぞ
- この記事は以下のソースコードの情報を元に作成しています
実例
おおまかな作り方はPlay作成画面で使える公式プリセットや、他の人が作ったPlayのソースを参考にしてください。
公式プリセット
Omikuji
ユーザーごとに日替わりのおみくじのプリセット
ソースコード
/// @ 0.12.4
// ユーザーごとに日替わりのおみくじのプリセット
// 選択肢
let choices = [
"ギガ吉"
"大吉"
"吉"
"中吉"
"小吉"
"末吉"
"凶"
"大凶"
]
// シードが「ユーザーID+今日の日付」である乱数生成器を用意
let random = Math:gen_rng(`{USER_ID}{Date:year()}{Date:month()}{Date:day()}`)
// ランダムに選択肢を選ぶ
let chosen = choices[random(0 (choices.len - 1))]
// 結果のテキスト
let result = `今日のあなたの運勢は **{chosen}** です。`
// UIを表示
Ui:render([
Ui:C:container({
align: 'center'
children: [
Ui:C:mfm({ text: result })
Ui:C:postFormButton({
text: "投稿する"
rounded: true
primary: true
form: {
text: `{result}{Str:lf}{THIS_URL}`
}
})
]
})
])
Shuffle
巻き戻し可能な文字シャッフルのプリセット
ソースコード
/// @ 0.12.4
// 巻き戻し可能な文字シャッフルのプリセット
let string = "ペペロンチーノ"
let length = string.len
// 過去の結果を保存しておくやつ
var results = []
// どれだけ巻き戻しているか
var cursor = 0
@do() {
if (cursor != 0) {
results = results.slice(0 (cursor + 1))
cursor = 0
}
let chars = []
for (let i, length) {
let r = Math:rnd(0 (length - 1))
chars.push(string.pick(r))
}
let result = chars.join("")
results.push(result)
// UIを表示
render(result)
}
@back() {
cursor = cursor + 1
let result = results[results.len - (cursor + 1)]
render(result)
}
@forward() {
cursor = cursor - 1
let result = results[results.len - (cursor + 1)]
render(result)
}
@render(result) {
Ui:render([
Ui:C:container({
align: 'center'
children: [
Ui:C:mfm({ text: result })
Ui:C:buttons({
buttons: [{
text: "←"
disabled: !(results.len > 1 && (results.len - cursor) > 1)
onClick: back
} {
text: "→"
disabled: !(results.len > 1 && cursor > 0)
onClick: forward
} {
text: "引き直す"
onClick: do
}]
})
Ui:C:postFormButton({
text: "投稿する"
rounded: true
primary: true
form: {
text: `{result}{Str:lf}{THIS_URL}`
}
})
]
})
])
}
do()
Timeline viewer
APIリクエストを行いローカルタイムラインを表示するプリセット
ソースコード
/// @ 0.12.4
// APIリクエストを行いローカルタイムラインを表示するプリセット
@fetch() {
Ui:render([
Ui:C:container({
align: 'center'
children: [
Ui:C:text({ text: "読み込み中..." })
]
})
])
// タイムライン取得
let notes = Mk:api("notes/local-timeline" {})
// それぞれのノートごとにUI要素作成
let noteEls = []
each (let note, notes) {
let el = Ui:C:container({
bgColor: "#444"
fgColor: "#fff"
padding: 10
rounded: true
children: [
Ui:C:mfm({
text: note.user.name
bold: true
})
Ui:C:mfm({
text: note.text
})
]
})
noteEls.push(el)
}
// UIを表示
Ui:render([
Ui:C:text({ text: "ローカル タイムライン" })
Ui:C:button({
text: "更新"
onClick: @() {
fetch()
}
})
Ui:C:container({
children: noteEls
})
])
}
fetch()
応用
地理クイズ (by @syuilo@misskey.io)
2048 (by @madorama_vrc@misskey.io)
パズルゲーム
FlappyUsachan (by @gozaru@misskey.io)
アクション要素のあるゲームも作れる。制作者による解説
サバイバルゲーム (by @mugcAp@misskey.io)
シミュレーション
ガチャシミュレーター (by @salano_ym@misskey.io)
排出対象のデータはPageから取得します。
参考記事
ゲームのイベント予定表 (by @salano_ym@misskey.io)
Pageに保存したデータを取得して表示します。ウィジェット利用向けにコードのアップデートを通知することもできます。(fetch関数参照)
他にも参考になるものがあれば教えてください!
UI操作
Ui:render
Ui:root.update({ children: [...] })
の糖衣構文
UIを1から表示するときはこれを使う
Ui:render([
Ui:C:text({text: "A"})
Ui:C:button({text: "B", onClick: @(){}})
])
Ui:get
コンポーネントをIDで取得。特定のコンポーネントのみ更新するときに使う
Ui:C:text({text: "A"}, "text1")
Ui:get("text1").update({text: "B"})
Ui:root
UIのルート。あまり使わないかも
Ui:root.update({
children: [ // 中身のコンポーネントの配列
Ui:C:text({text: "A"})
]
})
Ui:patch
未実装っぽい
UIコンポーネント
- コンポーネント定義の各要素は省略可能
-
component.id
でコンポーネントのIDを取得 -
component.update({...})
でコンポーネントを更新
UIデモ
表示系
Ui:C:text
MFMではない通常のテキスト。
Ui:C:text({
text: "内容" // 表示するテキスト
size: 1 // 文字サイズ
bold: false // ボールド
color: '#000' // 色
font: 'monospace' // フォント serif,sans-serif,monospace
})
Ui:C:mfm
MFMテキスト。
Ui:C:mfm({
text: "内容" // 表示するテキスト
size: 1 // 文字サイズ
bold: false // ボールド
color: '#000' // 色
font: 'monospace' // フォント serif,sans-serif,monospace
onClickEv: @(id) {
<: `{id} clicked` // $[clickable.ev=SOMEID TEXT]
}
})
入力系
Ui:C:button
ボタン。
var counter = 0
Ui:C:button({
text: "ボタン" // 表示するテキスト
onClick: @(){ counter += 1 } // 押したときのイベント
primary: false // 色を付けて強調
rounded: false // 角を丸く
disabled: false // 無効化
})
Ui:C:buttons
横並びの複数のボタン。
Ui:C:buttons({
buttons: [ // ボタン定義の配列 Ui:C:buttonと同じ
{text: "a", onClick: @(){...}}
{text: "b", onClick: @(){...}}
]
})
Ui:C:switch
ON/OFFのスイッチ
var func1_enabled = false
Ui:C:switch({
onChange: @(enabled) { // 変更された時のイベント
func1_enabled = enabled
}
default: false // デフォルト
label: "ラベル"
caption: "キャプション"
})
Ui:C:textarea
複数行のテキスト入力。
var the_text = ""
Ui:C:textarea({
onInput: @(text){ the_text = text } // 入力された時のイベント
default: "デフォルト"
label: "ラベル"
caption: "キャプション"
})
Ui:C:textInput
1行のテキスト入力。
var the_text = ""
Ui:C:textInput({
onInput: @(text){ the_text = text } // 入力された時のイベント
default: "デフォルト"
label: "ラベル"
caption: "キャプション"
})
Ui:C:numberInput
数値入力。
var the_number = 0
Ui:C:numberInput({
onInput: @(number){ the_number = number } // 入力された時のイベント
default: 0 // デフォルト
label: "ラベル"
caption: "キャプション"
})
Ui:C:select
複数の選択肢から1つ選ぶ。
var the_value = ""
Ui:C:select({
items: [ // 選択肢の配列
{text: "A", value: "v1"}
{text: "B", value: "v2"}
]
onChange: @(value){ the_value = value } // 変更された時のイベント
default: "v1" // デフォルト
label: "ラベル"
caption: "キャプション"
})
コンテナ系
Ui:C:container
幅寄せしたり色を付けたりする
Ui:C:container({
children: [Ui:C:text({text: "A"})] // 中身のコンポーネントの配列
align: 'center' // 幅寄せ left,center,right
bgColor: '#000' // 背景色
fgColor: '#00f' // 文字色
font: 'serif' // フォント serif,sans-serif,monospace
borderWidth: 1 // 枠幅
borderColor: '#f00' // 枠の色
padding: 1
rounded: false // 角を丸く
hidden: false // 隠す
})
Ui:C:folder
折りたためるフォルダ
Ui:C:folder({
children: [Ui:C:text({text: "A"})] // 中身のコンポーネントの配列
title: "タイトル"
opened: true // 開いているか
})
ノート投稿
Ui:C:postForm
Misskeyの投稿フォーム。(Misskey2023.9.0
から)
Ui:C:postForm({
form: {text: "投稿内容"} // 投稿フォームのデフォルト文字列
})
Ui:C:postFormButton
Misskeyの投稿フォームをポップアップ表示するボタン。
Ui:C:postFormButton({
text: "投稿!" // 表示するテキスト
primary: true // 色を付けて強調
rounded: true // 角を丸く
form: {text: "投稿内容"} // 投稿フォームのデフォルト文字列
})
ダイアログ
Mk:dialog
第3引数はinfo
,success
,warning
,error
,question
が指定可能。省略するとinfo
Mk:dialog("エラー!", "エラーが発生しました", "info")
Mk:confirm
ユーザーがOK
を押すとtrue
、キャンセル
を押すとfalse
が返る。
let ok = Mk:confirm("確認", "実行しますか?", "info")
readline
Misskey上では文字列入力のダイアログが表示される。
let name = readline('名前を入力してください')
セーブ・ロード
ローカルに保存される。
Mk:save
Mk:save("cookie_count", 9999)
Mk:load
let cookie_count = Mk:load("cookie_count")
Misskey API
Mk:api
Mk:api(ENDPOINT, PARAMETER, TOKEN)
APIドキュメント
Mk:api("notes/local-timeline", {})