Misskey Play is a new feature introduced in Misskey 13, which allows you to make interactive experiences using AI Script, which is built into Misskey.
Below are translated versions from Japanese to English of the examples provided in Misskey.
Below are translated versions from Japanese to English of the examples provided in Misskey.
Omikuji
Code:
/// @ 0.16.0
// Omikuji Preset that changes from day by day from user things.
// Voices
let choices = [
"Giga Luck"
“Excellent Luck"
"Good Luck"
"Considerable Luck"
"Modest Luck"
"Future Luck"
"Unlucky"
"Very Bad Luck"
]
// Prepare a random number generator whose seed is "user ID + today's date"
let random = Math:gen_rng(`{USER_ID}{Date:year()}{Date:month()}{Date:day()}`)
// Randomly choose a choice
let chosen = choices[random(0 (choices.len - 1))]
// Result text
let result = `Your fortune today is **{chosen}** .`
// Show UI
Ui:render([
Ui:C:container({
align: 'center'
children: [
Ui:C:mfm({ text: result })
Ui:C:postFormButton({
text: "Post"
rounded: true
primary: true
form: {
text: `{result}{Str:lf}{THIS_URL}`
}
})
]
})
])
Shuffle
Code:
/// @ 0.16.0
// Rewind ability character shuffle preset.
let string = "Peperoncino"
let length = string.len
// The one that saves past results
var results = []
// How much do you rewind?
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)
// Show 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: "Redraw"
onClick: do
}]
})
Ui:C:postFormButton({
text: "Post"
rounded: true
primary: true
form: {
text: `{result}{Str:lf}{THIS_URL}`
}
})
]
})
])
}
do()
Quiz
Code:
/// @ 0.16.0
let title = 'Geography Quiz'
let qas = [{
q: 'Australia capital is?'
choices: ['Sydney' 'Canberra' 'Melbourne']
a: 'Canberra'
aDescription: 'The largest city is Sydney, but the capital is Canberra.'
} {
q: 'What is the second country with the land area?'
choices: ['Canada' 'America' 'China']
a: 'Canada'
aDescription: 'Russia, Canada, the United States, and China in order of largest。'
} {
q: 'What is not a dual landlocked country?'
choices: ['Liechtenstein' 'Uzbekistan' 'Lesotho']
a: 'Lesotho'
aDescription: 'Lesotho is a (one-fold) landlocked country.'
} {
q: 'What is the canal without a lock?'
choices: ['Kiel Canal' 'The Suez Canal' 'The Panama Canal']
a: 'The Suez Canal'
aDescription: 'The Suez Canal has no height difference, so there is no lock.'
}]
let qaEls = [Ui:C:container({
align: 'center'
children: [
Ui:C:text({
size: 1.5
bold: true
text: title
})
]
})]
var qn = 0
each (let qa, qas) {
qn += 1
qa.id = Util:uuid()
qaEls.push(Ui:C:container({
align: 'center'
bgColor: '#000'
fgColor: '#fff'
padding: 16
rounded: true
children: [
Ui:C:text({
text: `Q{qn} {qa.q}`
})
Ui:C:select({
items: qa.choices.map(@(c) {{ text: c, value: c }})
onChange: @(v) { qa.userAnswer = v }
})
Ui:C:container({
children: []
} `{qa.id}:a`)
]
} qa.id))
}
@finish() {
var score = 0
each (let qa, qas) {
let correct = qa.userAnswer == qa.a
if (correct) score += 1
let el = Ui:get(`{qa.id}:a`)
el.update({
children: [
Ui:C:text({
size: 1.2
bold: true
color: if (correct) '#f00' else '#00f'
text: if (correct) '🎉Correct!' else 'Incorrect!'
})
Ui:C:text({
text: qa.aDescription
})
]
})
}
let result = `{title}’s results are {qas.len} questions with {score} answered correctly。`
Ui:get('footer').update({
children: [
Ui:C:postFormButton({
text: '結果を共有'
rounded: true
primary: true
form: {
text: `{result}{Str:lf}{THIS_URL}`
}
})
]
})
}
qaEls.push(Ui:C:container({
align: 'center'
children: [
Ui:C:button({
text: 'Check Answers'
primary: true
rounded: true
onClick: finish
})
]
} 'footer'))
Ui:render(qaEls)
Timeline
Code:
/// @ 0.16.0
// Preset that shows the local timeline using API requests
@fetch() {
Ui:render([
Ui:C:container({
align: 'center'
children: [
Ui:C:text({ text: "Loading..." })
]
})
])
// Timeline acquisition
let notes = Mk:api("notes/local-timeline" {})
// Create UI elements for each note
let noteEls = []
each (let note, notes) {
// Accounts that do not have a display name display id
let userName = if Core:type(note.user.name) == "str" note.user.name else note.user.username
// Set an alternative display sentence for notes with only renotes or media and voting and no text
let noteText = if Core:type(note.text) == "str" note.text else "(Re-note or media/vote-only note)"
let el = Ui:C:container({
bgColor: "#444"
fgColor: "#fff"
padding: 10
rounded: true
children: [
Ui:C:mfm({
text: userName
bold: true
})
Ui:C:mfm({
text: noteText
})
]
})
noteEls.push(el)
}
// Show UI
Ui:render([
Ui:C:text({ text: "Local Timeline" })
Ui:C:button({
text: "Refresh"
onClick: @() {
fetch()
}
})
Ui:C:container({
children: noteEls
})
])
}
fetch()