diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..91c5032
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,3 @@
+###### 下記の問題を説明してください。 スクリーンショットと診断情報を含めてください。
+###### Describe the problem you are having below. Please include a screenshot and the diagnostic information.
+
diff --git a/public/src/css/main.css b/public/src/css/main.css
index b91867a..c188c95 100644
--- a/public/src/css/main.css
+++ b/public/src/css/main.css
@@ -12,8 +12,10 @@ body{
width: 100%;
height: 100%;
background: #fe7839;
+ position: absolute;
user-select: none;
touch-action: none;
+ overflow: hidden;
}
#screen{
width: 100%;
@@ -135,30 +137,34 @@ body{
#tutorial{
background: rgb(246, 234, 212);
color: black;
- border: 5px black solid;
- border-radius: 10px;
- height: 65%;
- max-width: 800px;
- padding: 20px;
- margin: 8px;
- font-size: 16pt;
+ border: 0.25em black solid;
+ border-radius: 0.5em;
+ width: 800px;
+ padding: 1em;
+ margin: 1em;
+ font-size: 21px;
position: relative;
}
+.touch-enabled #tutorial{
+ font-size: 3vmin;
+}
#tutorial-title{
z-index: 1;
position: absolute;
color: white;
- top: -25px;
- font-size: 26pt;
+ top: -0.7em;
+ font-size: 1.65em;
}
#tutorial-content{
- padding: 15px 30px;
+ margin: 0.7em 0;
+ overflow-y: auto;
+ max-height: calc(100vh - 14em);
}
kbd{
font-family: inherit;
padding: 0.1em 0.6em;
border: 1px solid #ccc;
- font-size: 13px;
+ font-size: 0.6em;
background-color: #f7f7f7;
color: #333;
box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset;
@@ -169,33 +175,69 @@ kbd{
white-space: nowrap;
}
.taibtn{
- bottom: 15px;
- margin: 0 auto;
- position: absolute;
- right: 15px;
- padding: 10px 40px;
- border-radius: 15px;
- border: 3px rgba(218, 205, 178, 1) solid;
+ display: inline-block;
+ padding: 0.4em 0.4em;
+ border-radius: 0.5em;
+ border: 0.1em rgba(218, 205, 178, 1) solid;
cursor: pointer;
-}
-.taibtn:hover{
- z-index: 1;
- color: white;
- background: rgb(255, 181, 71);
- border-color: white;
-}
-.taibtn::before{
- padding: 0 40px;
+ font-size: 1.4em;
+ box-sizing: border-box;
+ color: #555;
+ text-align: center;
}
#tutorial-end-button{
- font-size: 22pt;
+ float: right;
+ padding: 0.4em 1.5em;
+ font-weight: bold;
+ border-color: #000;
+ color: #000;
+}
+.taibtn:hover,
+#tutorial-end-button:hover{
+ position: relative;
+ z-index: 1;
+ color: #fff;
+ background: #ffb547;
+ border-color: #fff;
+}
+.taibtn::before{
+ padding-left: inherit;
+}
+#about-link-btns{
+ float: left;
+ display: flex;
+}
+#about-link-btns .taibtn{
+ margin-right: 0.4em;
+}
+#diag-txt textarea,
+#diag-txt iframe{
+ width: 100%;
+ height: 5em;
+ font-size: inherit;
+ resize: none;
+ word-break: break-all;
+ margin-bottom: 1em;
+ background: #fff;
+ border: 1px solid #a9a9a9;
+}
+.text-warn{
+ color: #d00;
+}
+.link-btn a{
+ color: inherit;
+ text-decoration: none;
+ pointer-events: none;
+}
+.nowrap{
+ white-space: nowrap;
}
@keyframes bgscroll{
from{
- background-position: 0 center;
+ background-position: 0 top;
}
to{
- background-position: calc(-100vh / 720 * 512) center;
+ background-position: calc(-100vh / 720 * 512) top;
}
}
#song-select{
@@ -210,9 +252,7 @@ kbd{
}
#song-sel-canvas{
position: absolute;
- top: 0;
right: 0;
- bottom: 0;
left: 0;
margin: auto;
}
diff --git a/public/src/js/about.js b/public/src/js/about.js
new file mode 100644
index 0000000..a5e52c4
--- /dev/null
+++ b/public/src/js/about.js
@@ -0,0 +1,149 @@
+class About{
+ constructor(touchEnabled){
+ this.issueTemplate = [
+ "###### 下記の問題を説明してください。 スクリーンショットと診断情報を含めてください。",
+ "###### Describe the problem you are having below. Please include a screenshot and the diagnostic information."
+ ]
+
+ this.touchEnabled = touchEnabled
+ loader.changePage("about")
+ cancelTouch = false
+
+ this.endButton = document.getElementById("tutorial-end-button")
+ this.diagTxt = document.getElementById("diag-txt")
+ this.version = document.getElementById("version-link").href
+ this.tutorialOuter = document.getElementById("tutorial-outer")
+ if(touchEnabled){
+ this.tutorialOuter.classList.add("touch-enabled")
+ }
+ this.linkGithub = document.getElementById("link-github")
+ this.linkEmail = document.getElementById("link-email")
+
+ pageEvents.add(this.linkGithub, ["click", "touchend"], this.linkButton.bind(this))
+ pageEvents.add(this.linkEmail, ["click", "touchend"], this.linkButton.bind(this))
+ pageEvents.once(this.endButton, ["mousedown", "touchstart"]).then(this.onEnd.bind(this))
+ pageEvents.keyOnce(this, 13, "down").then(this.onEnd.bind(this))
+
+ this.gamepad = new Gamepad({
+ "confirm": ["start", "b", "ls", "rs"]
+ }, this.onEnd.bind(this))
+
+ this.addDiag()
+ }
+ onEnd(event){
+ var touched = false
+ if(event && event.type === "touchstart"){
+ event.preventDefault()
+ touched = true
+ }
+ this.clean()
+ assets.sounds["don"].play()
+ localStorage.setItem("tutorial", "true")
+ setTimeout(() => {
+ new SongSelect("about", false, touched)
+ }, 500)
+ }
+ addDiag(){
+ var diag = []
+
+ diag.push("```")
+ diag.push("Taiko-Web version: " + this.version)
+ diag.push("User agent: " + navigator.userAgent)
+ diag.push("Screen size: " + innerWidth + "x" + innerHeight + ", outer: " + outerWidth + "x" + outerHeight + ", ratio: " + (window.devicePixelRatio || 1).toFixed(2))
+ if(this.touchEnabled){
+ diag.push("Touch enabled: true")
+ }
+ if(!fullScreenSupported){
+ diag.push("Full screen supported: false")
+ }
+ diag.push("Blur performance: " + perf.blur + "ms, all images: " + perf.allImg + "ms")
+ diag.push("Page load: " + (perf.load / 1000).toFixed(1) + "s")
+ if("getGamepads" in navigator){
+ var gamepads = navigator.getGamepads()
+ for(var i = 0; i < gamepads.length; i++){
+ if(gamepads[i]){
+ var gamepadDiag = []
+ gamepadDiag.push(gamepads[i].id)
+ gamepadDiag.push("buttons: " + gamepads[i].buttons.length)
+ gamepadDiag.push("axes: " + gamepads[i].axes.length)
+ diag.push("Gamepad #" + (i + 1) + ": " + gamepadDiag.join(", "))
+ }
+ }
+ }
+ var errorObj = {}
+ if(localStorage["lastError"]){
+ try{
+ errorObj = JSON.parse(localStorage["lastError"])
+ }catch(e){}
+ }
+ if(errorObj.timestamp && errorObj.stack){
+ if(errorObj.timestamp + 1000 * 60 * 60 * 24 > (+new Date)){
+ diag.push("Last error: " + errorObj.stack)
+ diag.push("Error date: " + new Date(errorObj.timestamp).toGMTString())
+ }else{
+ localStorage.removeItem("lastError")
+ }
+ }
+ diag.push("```")
+ var diag = diag.join("\n")
+
+ if(navigator.userAgent.indexOf("Android") >= 0){
+ var iframe = document.createElement("iframe")
+ this.diagTxt.appendChild(iframe)
+ var body = iframe.contentWindow.document.body
+ body.innerText = diag
+
+ body.setAttribute("style", `
+ font-family: monospace;
+ margin: 2px 0 0 2px;
+ white-space: pre-wrap;
+ word-break: break-all;
+ cursor: text;
+ `)
+ body.setAttribute("onblur", `
+ getSelection().removeAllRanges()
+ `)
+ }else{
+ this.textarea = document.createElement("textarea")
+ this.textarea.readOnly = true
+ this.textarea.value = diag
+ this.diagTxt.appendChild(this.textarea)
+ if(!this.touchEnabled){
+ pageEvents.add(this.textarea, "focus", () => {
+ this.textarea.select()
+ })
+ pageEvents.add(this.textarea, "blur", () => {
+ getSelection().removeAllRanges()
+ })
+ }
+ }
+
+ var issueBody = this.issueTemplate.join("\n") + "\n\n\n\n" + diag
+ this.getLink(this.linkGithub).href += "?body=" + encodeURIComponent(issueBody)
+ this.getLink(this.linkEmail).href += "?body=" + encodeURIComponent(issueBody.replace(/\n/g, "
\r\n"))
+ }
+ getLink(target){
+ return target.getElementsByTagName("a")[0]
+ }
+ linkButton(event){
+ this.getLink(event.currentTarget).click()
+ }
+ clean(){
+ cancelTouch = true
+ this.gamepad.clean()
+ pageEvents.remove(this.linkGithub, ["click", "touchend"])
+ pageEvents.remove(this.linkEmail, ["click", "touchend"])
+ pageEvents.remove(this.endButton, ["mousedown", "touchstart"])
+ if(this.textarea){
+ pageEvents.remove(this.textarea, ["focus", "blur"])
+ }
+ pageEvents.keyRemove(this, 13)
+ delete this.endButton
+ delete this.diagTxt
+ delete this.version
+ delete this.tutorialOuter
+ delete this.linkGithub
+ delete this.linkEmail
+ delete this.textarea
+ }
+}
diff --git a/public/src/js/assets.js b/public/src/js/assets.js
index e289e16..fde1bec 100644
--- a/public/src/js/assets.js
+++ b/public/src/js/assets.js
@@ -123,7 +123,8 @@ var assets = {
"loadsong.html",
"songselect.html",
"titlescreen.html",
- "tutorial.html"
+ "tutorial.html",
+ "about.html"
],
"songs": [],
diff --git a/public/src/js/canvastest.js b/public/src/js/canvastest.js
index b952981..dea0bf6 100644
--- a/public/src/js/canvastest.js
+++ b/public/src/js/canvastest.js
@@ -91,6 +91,7 @@ class CanvasTest{
drawAllImages(){
return new Promise(resolve => {
requestAnimationFrame(() => {
+ var startTime = +new Date
var ctx = this.ctx
ctx.save()
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
@@ -131,7 +132,7 @@ class CanvasTest{
}
ctx.restore()
- resolve()
+ resolve((+new Date) - startTime)
})
})
}
diff --git a/public/src/js/loader.js b/public/src/js/loader.js
index e8bda9d..59954b6 100644
--- a/public/src/js/loader.js
+++ b/public/src/js/loader.js
@@ -5,16 +5,9 @@ class Loader{
this.assetsDiv = document.getElementById("assets")
this.canvasTest = new CanvasTest()
p2 = new P2Connection()
- this.ajax("src/views/loader.html").then(this.run.bind(this))
+ this.startTime = +new Date
- pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
- event.preventDefault()
- })
- var versionDiv = document.getElementById("version")
- var versionLink = document.getElementById("version-link")
- pageEvents.add(versionDiv, ["click", "touchend"], () => {
- versionLink.click()
- })
+ this.ajax("src/views/loader.html").then(this.run.bind(this))
}
run(page){
this.promises = []
@@ -94,6 +87,7 @@ class Loader{
})
this.promises.push(this.canvasTest.blurPerformance().then(result => {
+ perf.blur = result
if(result > 1000 / 50){
// Less than 50 fps with blur enabled
disableBlur = true
@@ -105,7 +99,9 @@ class Loader{
})
Promise.all(this.promises).then(() => {
- this.canvasTest.drawAllImages().then(() => {
+ this.canvasTest.drawAllImages().then(result => {
+ perf.allImg = result
+ perf.load = (+new Date) - this.startTime
this.canvasTest.clean()
this.clean()
this.callback()
diff --git a/public/src/js/main.js b/public/src/js/main.js
index 98f6121..7647985 100644
--- a/public/src/js/main.js
+++ b/public/src/js/main.js
@@ -1,3 +1,16 @@
+addEventListener("error", err => {
+ var stack
+ if("error" in err){
+ stack = err.error.stack
+ }else{
+ stack = err.message + "\n at " + err.filename + ":" + err.lineno + ":" + err.colno
+ }
+ localStorage["lastError"] = JSON.stringify({
+ timestamp: +new Date,
+ stack: stack
+ })
+})
+
function toggleFullscreen(){
if("requestFullscreen" in root){
if(document.fullscreenElement){
@@ -19,6 +32,14 @@ function toggleFullscreen(){
}
}
}
+
+function resizeRoot(){
+ if(lastHeight !== innerHeight){
+ lastHeight = innerHeight
+ root.style.height = innerHeight + "px"
+ }
+}
+
var root = document.documentElement
var fullScreenSupported = "requestFullscreen" in root || "webkitRequestFullscreen" in root || "mozRequestFullScreen" in root
@@ -26,6 +47,27 @@ var pageEvents = new PageEvents()
var snd = {}
var p2
var disableBlur = false
+var cancelTouch = true
+var lastHeight
+var perf = {
+ blur: 0,
+ allImg: 0,
+ load: 0
+}
+
+pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
+ if(event.cancelable && cancelTouch){
+ event.preventDefault()
+ }
+})
+var versionDiv = document.getElementById("version")
+var versionLink = document.getElementById("version-link")
+pageEvents.add(versionDiv, ["click", "touchend"], () => {
+ versionLink.click()
+})
+resizeRoot()
+setInterval(resizeRoot, 100)
+
var loader = new Loader(() => {
new Titlescreen()
})
diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js
index 41c57e2..f2b3fdd 100644
--- a/public/src/js/scoresheet.js
+++ b/public/src/js/scoresheet.js
@@ -115,7 +115,7 @@ class Scoresheet{
ctx.save()
var winW = innerWidth
- var winH = innerHeight
+ var winH = lastHeight
this.pixelRatio = window.devicePixelRatio || 1
winW *= this.pixelRatio
winH *= this.pixelRatio
diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js
index 53248e9..61a4641 100644
--- a/public/src/js/songselect.js
+++ b/public/src/js/songselect.js
@@ -29,6 +29,12 @@ class SongSelect{
border: ["#d6ffff", "#6bae9c"],
outline: "#31ae94"
},
+ "about": {
+ sort: 7,
+ background: "#91cfff",
+ border: ["#dff0ff", "#6890b2"],
+ outline: "#217abb"
+ },
"J-POP": {
sort: 0,
background: "#219fbb",
@@ -114,7 +120,9 @@ class SongSelect{
category: "ランダム"
})
if(touchEnabled){
- fromTutorial = false
+ if(fromTutorial === "tutorial"){
+ fromTutorial = false
+ }
}else{
this.songs.push({
title: "あそびかた説明",
@@ -123,6 +131,12 @@ class SongSelect{
category: "ランダム"
})
}
+ this.songs.push({
+ title: "について",
+ skin: this.songSkin.about,
+ action: "about",
+ category: "ランダム"
+ })
this.songs.push({
title: "もどる",
skin: this.songSkin.back,
@@ -155,16 +169,20 @@ class SongSelect{
this.selectedDiff = 0
assets.sounds["bgm_songsel"].playLoop(0.1, false, 0, 1.442, 3.506)
- if(touchEnabled || !fromTutorial && "selectedSong" in localStorage){
+ if(!fromTutorial && !("selectedSong" in localStorage)){
+ fromTutorial = touchEnabled ? "about" : "tutorial"
+ }
+
+ if(fromTutorial){
+ this.selectedSong = this.songs.findIndex(song => song.action === fromTutorial)
+ this.playBgm(true)
+ }else{
if("selectedSong" in localStorage){
this.selectedSong = Math.min(Math.max(0, localStorage["selectedSong"] |0), this.songs.length)
}
assets.sounds["song-select"].play()
snd.musicGain.fadeOut()
this.playBgm(false)
- }else{
- this.selectedSong = this.songs.findIndex(song => song.action === "tutorial")
- this.playBgm(true)
}
if("selectedDiff" in localStorage){
this.selectedDiff = Math.min(Math.max(0, localStorage["selectedDiff"] |0), 4)
@@ -454,6 +472,8 @@ class SongSelect{
}, 200)
}else if(currentSong.action === "tutorial"){
this.toTutorial()
+ }else if(currentSong.action === "about"){
+ this.toAbout()
}
this.pointer(false)
}
@@ -505,6 +525,13 @@ class SongSelect{
new Tutorial(true)
}, 500)
}
+ toAbout(){
+ assets.sounds["don"].play()
+ this.clean()
+ setTimeout(() => {
+ new About(this.touchEnabled)
+ }, 500)
+ }
redraw(){
if(!this.redrawRunning){
@@ -538,7 +565,7 @@ class SongSelect{
var ctx = this.ctx
var winW = innerWidth
- var winH = innerHeight
+ var winH = lastHeight
if(winW / 32 > winH / 9){
winW = winH / 9 * 32
}
diff --git a/public/src/js/tutorial.js b/public/src/js/tutorial.js
index 3f9e1e3..b340d2c 100644
--- a/public/src/js/tutorial.js
+++ b/public/src/js/tutorial.js
@@ -22,7 +22,7 @@ class Tutorial{
assets.sounds["don"].play()
localStorage.setItem("tutorial", "true")
setTimeout(() => {
- new SongSelect(this.fromSongSel, false, touched)
+ new SongSelect(this.fromSongSel ? "tutorial" : false, false, touched)
}, 500)
}
clean(){
diff --git a/public/src/js/view.js b/public/src/js/view.js
index 99d37ae..a9f5dcf 100644
--- a/public/src/js/view.js
+++ b/public/src/js/view.js
@@ -949,8 +949,10 @@ class View{
}
clean(){
pageEvents.mouseRemove(this)
- if(this.controller.multiplayer === 2 && this.canvas){
- this.canvas.canvas.parentNode.removeChild(this.canvas.canvas)
+ if(this.controller.multiplayer === 2){
+ if(this.canvas){
+ this.canvas.canvas.parentNode.removeChild(this.canvas.canvas)
+ }
}else{
this.cursor.parentNode.removeChild(this.cursor)
}
diff --git a/public/src/views/about.html b/public/src/views/about.html
new file mode 100644
index 0000000..5777ea2
--- /dev/null
+++ b/public/src/views/about.html
@@ -0,0 +1,27 @@
+