From 838442d2f62603f786c2aee0d264d729c1ae886d Mon Sep 17 00:00:00 2001
From: sora <34794115+skyventuree@users.noreply.github.com>
Date: Thu, 5 May 2022 22:03:45 +0700
Subject: [PATCH 1/3] fast fix
---
styles/main.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/styles/main.css b/styles/main.css
index 8427bb4..06aa2ce 100644
--- a/styles/main.css
+++ b/styles/main.css
@@ -20,7 +20,7 @@ body {
font-size: 18px;
background-color: #FF0405;
overflow-x: hidden;
- background: url("/assets/background.jpg") no-repeat center center fixed;
+ background: url("../assets/background.jpg") no-repeat center center fixed;
}
body, div {
From 7c8e4e6098cf6b7cbbea8d34c37b3d9f27b2c15a Mon Sep 17 00:00:00 2001
From: sora <34794115+skyventuree@users.noreply.github.com>
Date: Thu, 5 May 2022 22:06:01 +0700
Subject: [PATCH 2/3] Revert "Merge branch 'main' into dev"
This reverts commit aeaff9d5daba6d4f724405a391321c72932bf418, reversing
changes made to 6d3279fa0d9ab1dc97690b7337c9510c181c6d27.
---
.github/workflows/action.yml | 4 +-
app.js | 21 +++-
scripts/card.js | 105 +++++++++++++++-
scripts/editor.js | 64 +++++++++-
scripts/exporter.js | 19 ++-
scripts/textgen/char.js | 95 ++++++++++++++-
scripts/textgen/text.js | 227 ++++++++++++++++++++++++++++++++++-
scripts/textgen/utils.js | 79 +++++++++++-
styles/button.css | 2 +-
styles/editor.css | 149 ++++++++++++++++++++++-
styles/main.css | 2 +-
version.js | 2 +
12 files changed, 757 insertions(+), 12 deletions(-)
diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml
index b19ceef..d372c9e 100644
--- a/.github/workflows/action.yml
+++ b/.github/workflows/action.yml
@@ -1,7 +1,7 @@
name: Minify Workflow - P5CC
on:
push:
- branches: [ main ]
+ branches: [ prod ]
jobs:
build:
@@ -20,4 +20,4 @@ jobs:
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Minify source code
- branch: ${{ github.ref }}
+ branch: ${{ github.ref }}
\ No newline at end of file
diff --git a/app.js b/app.js
index 2956ede..9c5348a 100644
--- a/app.js
+++ b/app.js
@@ -1 +1,20 @@
-const express=require("express"),favicon=require("serve-favicon"),app=express(),port=4200;app.use(express.static(".")),app.use(favicon("./favicon.ico")),app.get("/",((e,s)=>{s.send("try /index.html")})),app.listen(4200,(()=>{console.info("p5cc launched"),console.log("localhost:4200")}));
+// Persona 5 Calling Card - Express Static Page (@skyventuree)
+// While it's possible to open the webpage in your browser through the `file://` protocol,
+// due to security issues, downloading image and some feature won't be available without using localhost.
+const express = require('express');
+const favicon = require('serve-favicon');
+const app = express();
+
+const port = 4200; // make sure the port you are using is not in use by other apps
+
+app.use(express.static('.'));
+app.use(favicon('./favicon.ico'));
+
+app.get('/', (req, res) => {
+ res.send("try /index.html");
+})
+
+app.listen(port, () => {
+ console.info("p5cc launched");
+ console.log('localhost:' + port);
+})
\ No newline at end of file
diff --git a/scripts/card.js b/scripts/card.js
index c1b48dd..73c211d 100644
--- a/scripts/card.js
+++ b/scripts/card.js
@@ -1 +1,104 @@
-var canvas=document.getElementById("canvas-card"),card=canvas.getContext("2d");card.font="34px KoreanKRSM";var baseCard=new Image;baseCard.src="assets/base.png",baseCard.onload=redrawBg;var logo=new Image;function redrawBg(){const e=document.querySelector("#logo-size-option").value,t=document.querySelector("#logo-offset").value;card.clearRect(0,0,canvas.width,canvas.height),card.drawImage(baseCard,0,0),showLogo&&card.drawImage(logo,canvas.width-250*e-t,canvas.height-291*e-t,250*e,291*e),showWtm&&(card.fillStyle="rgba(255, 255, 255, 0.65)",card.textAlign="left",card.fillText("skyventuree.github.io/p5cc",30,canvas.height-30))}logo.src="assets/logo.png",logo.onload=redrawBg;const textInput=document.querySelector("#content > textarea"),fontSizeInput=document.querySelector("#font-size"),fontFamilyInput=document.querySelector("#font-family"),lineCanvas=document.createElement("canvas"),canvasText=document.getElementById("canvas-text"),textCtx=canvasText.getContext("2d");let box;function redrawText(){const e=Number(document.querySelector('#delay-rate > input[type="number"]').value),t=Math.min(Math.abs(+fontSizeInput.value||120)),a=fontFamilyInput.value||"sans-serif";lineCanvas.width=canvasText.width,lineCanvas.height=2.2*t,textCtx.clearRect(0,0,canvasText.width,canvasText.height);const n=(textInput.value||"TAKE YOUR HEART").trim(),o=n.split("\n");let c=0,r=0,l=0,s=Number(document.querySelector("#text-top").value),u=0;o.forEach((d=>{setTimeout((()=>{box=new BoxText(d,{fontSize:t,fontFamily:a}),isMiddle&&(s=0,r=(canvasText.height-t*o.length)/2.5-t/5*o.length),l+=Number(box.draw(lineCanvas)-40),textCtx.drawImage(lineCanvas,0,c+r+s),c=Math.floor(l)||c,console.log(n,c,r,l)}),u),u+=e}))}const checkText=setInterval((()=>{textInput.value!==textInput.lastValue&&(textInput.lastValue=textInput.value,redrawText())}),1e3);
+// P5CC core functions
+var canvas = document.getElementById("canvas-card");
+var card = canvas.getContext("2d");
+
+card.font = '34px KoreanKRSM';
+
+// load base card first
+var baseCard = new Image();
+baseCard.src = "assets/base.png";
+baseCard.onload = redrawBg;
+
+// logo initial size: 250 × 291
+var logo = new Image();
+logo.src = "assets/logo.png";
+logo.onload = redrawBg;
+
+// for the card canvas
+function redrawBg() {
+ // asset calculations
+ const logoScale = document.querySelector('#logo-size-option').value;
+ const logoOffset = document.querySelector('#logo-offset').value;
+
+ let logoWidth = 250;
+ let logoHeight = 291;
+
+ card.clearRect(0, 0, canvas.width, canvas.height);
+ card.drawImage(baseCard, 0, 0);
+
+ if (showLogo) {
+ card.drawImage(logo,
+ canvas.width - (logoWidth * logoScale) - logoOffset,
+ canvas.height - (logoHeight * logoScale) - logoOffset,
+ logoWidth * logoScale,
+ logoHeight * logoScale);
+ }
+
+ if (showWtm) {
+ card.fillStyle = 'rgba(255, 255, 255, 0.65)';
+ card.textAlign = 'left';
+ card.fillText('skyventuree.github.io/p5cc', 30, canvas.height - 30);
+ }
+}
+
+// for the text canvas
+const textInput = document.querySelector('#content > textarea');
+const fontSizeInput = document.querySelector('#font-size');
+const fontFamilyInput = document.querySelector('#font-family');
+
+const lineCanvas = document.createElement('canvas');
+
+const canvasText = document.getElementById("canvas-text");
+const textCtx = canvasText.getContext('2d');
+let box;
+
+function redrawText() {
+ const delay = Number(document.querySelector('#delay-rate > input[type="number"]').value);
+ const fontSize = Math.min(Math.abs(+fontSizeInput.value || 120));
+ const fontFamily = fontFamilyInput.value || 'sans-serif';
+
+ // another canvas so making multiline text is easier
+ lineCanvas.width = canvasText.width;
+ lineCanvas.height = fontSize * 2.2;
+
+ textCtx.clearRect(0, 0, canvasText.width, canvasText.height);
+
+ const value = (textInput.value || 'TAKE YOUR HEART').trim();
+ const splitValue = value.split('\n');
+
+ // they are all offset, just a different name and purpose
+ let lineHeight = 0, middleOffset = 0, heightOffset = 0;
+ let topOffset = Number(document.querySelector('#text-top').value);
+ let timer = 0;
+
+ splitValue.forEach(line => {
+ setTimeout(() => {
+ box = new BoxText(line, {
+ fontSize,
+ fontFamily
+ });
+
+ if (isMiddle) {
+ topOffset = 0;
+ middleOffset = ((canvasText.height - fontSize * splitValue.length) / 2.5) - (fontSize / 5 * (splitValue.length));
+ }
+
+ heightOffset += Number(box.draw(lineCanvas) - 40);
+
+ textCtx.drawImage(lineCanvas, 0, lineHeight + middleOffset + topOffset);
+
+ lineHeight = Math.floor(heightOffset) || lineHeight;
+ console.log(value, lineHeight, middleOffset, heightOffset);
+ }, timer);
+ timer += delay;
+ });
+
+}
+
+// check textarea to see if anything changes every 1s to avoid lag
+const checkText = setInterval(() => {
+ if (textInput.value !== textInput.lastValue) {
+ textInput.lastValue = textInput.value;
+ redrawText();
+ }
+}, 1000);
\ No newline at end of file
diff --git a/scripts/editor.js b/scripts/editor.js
index 2cf0326..31a9920 100644
--- a/scripts/editor.js
+++ b/scripts/editor.js
@@ -1 +1,63 @@
-var showLogo=!0,showWtm=!0,isMiddle=!0,textStroke=!1,textStrokeWidth=6;let defaults='Clear',confirm='Are you sure?';var confirming=!1;function clearCard(e){if(confirming)return document.querySelector("#content > textarea").value="",e.innerHTML=defaults,confirming=!1,void redrawText();e.innerHTML=confirm,confirming=!0,setTimeout((function(){e.innerHTML=defaults,confirming=!1}),1500)}function saveDelay(){let e=Number(document.querySelector('#delay-rate > input[type="number"]').value),t=new Date;t.setTime(t.getTime()+31536e6);let n="expires="+t.toUTCString();document.cookie=`delay=${e};${n};path=/`}window.onload=function(){console.info("Getting cookie value...");let e=document.cookie.replace(/(?:(?:^|.*;\s*)delay\s*\=\s*([^;]*).*$)|^.*$/,"$1");e&&(document.querySelector('#delay-rate > input[type="number"]').value=e),document.querySelector("#option-default").click()},document.getElementById("tab-handler").addEventListener("click",(function(e){if(e.target){var t=e.target.closest("button").dataset.textOption;Array.from(document.getElementsByClassName("options-tab")).forEach((function(e){e.style.display="none"}));var n=document.getElementsByClassName("tab-btn")[0].children;Array.from(n).forEach((function(e){e.classList.remove("active")})),document.getElementById(t).style.display="block",e.target.closest("button").classList.add("active")}}));
+// editor related switches and option
+var showLogo = true,
+ showWtm = true,
+ isMiddle = true,
+ textStroke = false,
+ textStrokeWidth = 6;
+
+// clearing the input field
+let defaults = 'Clear';
+let confirm = 'Are you sure?';
+var confirming = false;
+function clearCard(element) {
+
+ if (confirming) {
+ document.querySelector('#content > textarea').value = '';
+ element.innerHTML = defaults;
+ confirming = false;
+ redrawText();
+ return;
+ }
+
+ element.innerHTML = confirm;
+ confirming = true;
+
+ setTimeout(function() {
+ element.innerHTML = defaults;
+ confirming = false;
+ }, 1500);
+}
+
+// delay function
+function saveDelay() {
+ let delay = Number(document.querySelector('#delay-rate > input[type="number"]').value);
+ let date = new Date();
+ date.setTime(date.getTime() + (365 * 24 * 60 * 60 * 1000));
+ let expires = "expires=" + date.toUTCString();
+ document.cookie = `delay=${delay};${expires};path=/`;
+}
+
+window.onload = function() {
+ console.info("Getting cookie value...")
+ let delay = document.cookie.replace(/(?:(?:^|.*;\s*)delay\s*\=\s*([^;]*).*$)|^.*$/, "$1");
+ if (delay) {
+ document.querySelector('#delay-rate > input[type="number"]').value = delay;
+ }
+ document.querySelector('#option-default').click();
+}
+
+// tab handler for text options
+document.getElementById('tab-handler').addEventListener('click', function(e) {
+ if(e.target) {
+ var option = e.target.closest('button').dataset.textOption;
+
+ // disable all elements
+ Array.from(document.getElementsByClassName('options-tab')).forEach(function(e){e.style.display = 'none'})
+ var tabButton = document.getElementsByClassName('tab-btn')[0].children
+ Array.from(tabButton).forEach(function(e){e.classList.remove('active')})
+
+ // enable the selected element
+ document.getElementById(option).style.display = 'block';
+ e.target.closest('button').classList.add('active');
+ }
+});
\ No newline at end of file
diff --git a/scripts/exporter.js b/scripts/exporter.js
index 13f1031..738f61b 100644
--- a/scripts/exporter.js
+++ b/scripts/exporter.js
@@ -1 +1,18 @@
-function exportCard(){let e=document.querySelector("#canvas-card"),a=document.querySelector("#canvas-text");redrawBg();let t=e.getContext("2d");t.save(),t.drawImage(a,0,0);const r=canvas.toDataURL("image/png").replace("image/png","image/octet-stream"),c=document.createElement("a");c.href=r,c.download=`p5cc_${Math.floor(1e6*Math.random())}.png`,c.target="blank",c.click(),t.restore()}
+function exportCard() {
+ let card = document.querySelector('#canvas-card');
+ let text = document.querySelector('#canvas-text');
+ redrawBg();
+ let cardCtx = card.getContext('2d');
+
+ cardCtx.save()
+ cardCtx.drawImage(text, 0, 0);
+
+ const imageURL = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
+ const a = document.createElement('a');
+ a.href = imageURL;
+ a.download = `p5cc_${Math.floor(Math.random() * 1000000)}.png`;
+ a.target = 'blank';
+ a.click();
+
+ cardCtx.restore();
+}
\ No newline at end of file
diff --git a/scripts/textgen/char.js b/scripts/textgen/char.js
index 7f5e076..b9a9208 100644
--- a/scripts/textgen/char.js
+++ b/scripts/textgen/char.js
@@ -1 +1,94 @@
-const COLORS={RED:"#E5191C",WHITE:"#FDFDFD",BLACK:"#0F0F0F"},CHAR_MODE={FIRST:1,WHITE:2,RED:3,SPACE:4},MAX_ANGLE=10;class BoxChar{static BorderScale=1.4;static BackgroundScale=1.2;char="";fontFamily="";fontSize=0;width=0;height=0;left=0;top=0;angle=0;scale=0;mode=CHAR_MODE.WHITE;color=COLORS.WHITE;constructor(t,h,i=60,e="sans-serif"){if(this.char=t,this.mode=h,this.fontFamily=e,h==CHAR_MODE.SPACE)return;const a=-Math.round(10*Math.random())%10;h==CHAR_MODE.FIRST?(this.scale=1.1,this.angle=a):(this.scale=1-Math.floor(10*Math.random())%3/10,this.angle=a*randomOper()),this.fontSize=i*this.scale,h==CHAR_MODE.RED&&(this.color=COLORS.RED);const{width:s,height:o,top:r,left:n}=getCharSize(t,this.fontSize,this.fontFamily,"bold");this.width=s,this.height=o,this.top=r,this.left=n}get font(){return`bold ${this.fontSize}px ${this.fontFamily}`}get rotateSize(){const t=this.angle*Math.PI/180,h=Math.abs(Math.sin(t)),i=Math.abs(Math.cos(t));return{width:Math.ceil(this.width*i)+Math.ceil(this.height*h),height:Math.ceil(this.height*i)+Math.ceil(this.width*h)}}get outterSize(){const{width:t,height:h}=this.rotateSize,i=this.mode==CHAR_MODE.FIRST?BoxChar.BorderScale:BoxChar.BackgroundScale;return{width:t*i,height:h*i}}}
+const COLORS = {
+ RED: '#E5191C',
+ WHITE: '#FDFDFD',
+ BLACK: '#0F0F0F',
+}
+const CHAR_MODE = {
+ FIRST: 1,
+ WHITE: 2,
+ RED: 3,
+ SPACE: 4,
+};
+const MAX_ANGLE = 10;
+
+// handling individual box of characters
+class BoxChar {
+ static BorderScale = 1.4;
+ static BackgroundScale = 1.2;
+
+ char = '';
+ fontFamily = '';
+ fontSize = 0;
+ width = 0;
+ height = 0;
+ left = 0;
+ top = 0;
+ angle = 0;
+ scale = 0;
+ mode = CHAR_MODE.WHITE;
+ color = COLORS.WHITE;
+
+ constructor(char, mode, fontSize = 60, fontFamily = 'sans-serif') {
+ this.char = char;
+ this.mode = mode;
+ this.fontFamily = fontFamily;
+
+ if (mode == CHAR_MODE.SPACE) {
+ return;
+ }
+
+ const angle = -(Math.round(Math.random() * 10) % MAX_ANGLE);
+ if (mode == CHAR_MODE.FIRST) {
+ this.scale = 1.1;
+ this.angle = angle;
+ } else {
+ this.scale = 1 - Math.floor(Math.random() * 10) % 3 / 10;
+ this.angle = angle * randomOper();
+ }
+ this.fontSize = fontSize * this.scale;
+
+ if (mode == CHAR_MODE.RED) {
+ this.color = COLORS.RED;
+ }
+
+ const {
+ width,
+ height,
+ top,
+ left
+ } = getCharSize(char, this.fontSize, this.fontFamily, 'bold');
+ this.width = width;
+ this.height = height;
+ this.top = top;
+ this.left = left;
+ }
+
+ get font() {
+ return `bold ${this.fontSize}px ${this.fontFamily}`;
+ }
+
+ get rotateSize() {
+ const angle = this.angle * Math.PI / 180;
+ const sin = Math.abs(Math.sin(angle)),
+ cos = Math.abs(Math.cos(angle));
+ const width = Math.ceil(this.width * cos) + Math.ceil(this.height * sin);
+ const height = Math.ceil(this.height * cos) + Math.ceil(this.width * sin);
+ return {
+ width,
+ height
+ };
+ }
+
+ get outterSize() {
+ const {
+ width,
+ height
+ } = this.rotateSize;
+ const scale = this.mode == CHAR_MODE.FIRST ? BoxChar.BorderScale : BoxChar.BackgroundScale;
+ return {
+ width: width * scale,
+ height: height * scale
+ };
+ }
+
+}
\ No newline at end of file
diff --git a/scripts/textgen/text.js b/scripts/textgen/text.js
index ced4d11..0800f36 100644
--- a/scripts/textgen/text.js
+++ b/scripts/textgen/text.js
@@ -1 +1,226 @@
-class BoxText{chars=[];fontSize=120;fontFamily="sans-serif";gutter=5;pendding=30;constructor(t,e={}){if(e){const{fontSize:t,fontFamily:o,gutter:i,pendding:a}=e;t&&(this.fontSize=t),o&&(this.fontFamily=o),i&&(this.gutter=i),a&&(this.pendding=a)}t||console.error("Must set text.");const o=t.split(""),i=new Array(o.length).fill(CHAR_MODE.WHITE);i[0]=CHAR_MODE.FIRST;for(let t=1;t6){i[e]=CHAR_MODE.RED;break}for(const[t,e]of o.entries())/^\s$/.test(e)?this.chars.push(new BoxChar("",CHAR_MODE.SPACE)):this.chars.push(new BoxChar(e,i[t],this.fontSize,this.fontFamily))}draw(t){const e=t.getContext("2d");if(!e)return void console.error("Failed to load canvas");e.clearRect(0,0,t.width,t.height);const o=this.pendding,i=this.gutter;let a=2*o,n=0;for(const t of this.chars)if(t instanceof BoxChar){const e=t.outterSize;a+=e.width+i,n=Math.max(n,e.height)}else a+=2*i;const s=document.querySelector("#text-align");let l=0;"center"===s.value&&(l=(t.width-a)/2),"right"===s.value&&(l=t.width-a);let r=o+l;n+=2*o,e.fillStyle=COLORS.WHITE,e.textBaseline="top",e.textAlign="left";for(const t of this.chars){if(t.mode==CHAR_MODE.SPACE){r+=2*i;continue}e.save();let{char:a,top:s,left:l,width:h,height:f,angle:c,mode:d,color:g}=t;if(d==CHAR_MODE.FIRST){const{width:d,height:S}=t.outterSize,C=r+d/2,u=o+S/2;rotateCanvas(e,c-5,C,u),e.fillStyle=COLORS.BLACK,e.fillRect(r,(n-S)/2,d,S),rotateCanvas(e,c+3,C,u);const R=.85,w=d*R,x=S*R,O=r+(d-w)/2,m=(n-x)/2;e.fillStyle=COLORS.RED,e.fillRect(O,m,w,x),rotateCanvas(e,c+2,C,u);const v=r+(d-h)/2-l,p=(n-f)/2-s;e.fillStyle=g,e.font=t.font,e.fillText(a,v,p),r+=t.outterSize.width+i}else{const{width:d,height:S}=t.outterSize,C=r+d/2,u=o+S/2;rotateCanvas(e,c+1,C,u),e.fillStyle=COLORS.BLACK,e.fillRect(r,(n-S)/2,d,S);const R=r+(d-h)/2-l,w=(n-f)/2-s;rotateCanvas(e,-1,C,u),e.fillStyle=g,e.font=t.font,e.fillText(a,R,w),r+=t.outterSize.width+i}e.restore()}const h=e.getImageData(0,0,1770,1300),f=e.createImageData(1770,1300);if(textStroke){const t=parseInt(textStrokeWidth),e=Math.floor(t/2);for(let o=e;o 6) {
+ modes[j] = CHAR_MODE.RED;
+ break;
+ }
+ }
+ }
+
+ for (const [index, char] of chars.entries()) {
+ if (/^\s$/.test(char)) {
+ this.chars.push(new BoxChar('', CHAR_MODE.SPACE));
+ }
+ else {
+ this.chars.push(new BoxChar(char, modes[index], this.fontSize, this.fontFamily));
+ }
+ }
+ }
+
+ draw(canvas) {
+ const ctx = canvas.getContext('2d');
+
+ if (!ctx) {
+ console.error('Failed to load canvas');
+ return;
+ }
+
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ const pendding = this.pendding,
+ gutter = this.gutter;
+
+ let canvasWidth = pendding * 2,
+ canvasHeight = 0;
+
+
+ for (const boxChar of this.chars) {
+ if (boxChar instanceof BoxChar) {
+ const size = boxChar.outterSize;
+ canvasWidth += (size.width + gutter);
+ canvasHeight = Math.max(canvasHeight, size.height);
+ } else {
+ canvasWidth += 2 * gutter;
+ }
+ }
+
+ // offset for text alignment
+ const align = document.querySelector('#text-align');
+ let widthOffset = 0;
+ if (align.value === 'center') {
+ widthOffset = (canvas.width - canvasWidth) / 2;
+ }
+ if (align.value === 'right') {
+ widthOffset = canvas.width - canvasWidth;
+ }
+
+ let drawOffset = pendding + widthOffset;
+
+ canvasHeight = canvasHeight + pendding * 2;
+
+ ctx.fillStyle = COLORS.WHITE;
+ ctx.textBaseline = 'top';
+ ctx.textAlign = 'left';
+
+ /* CHARACTERS DRAWINGS */
+ for (const boxChar of this.chars) {
+ if (boxChar.mode == CHAR_MODE.SPACE) {
+ drawOffset += 2 * gutter;
+ continue;
+ }
+
+ ctx.save();
+
+ let {
+ char,
+ top,
+ left,
+ width,
+ height,
+ angle,
+ mode,
+ color
+ } = boxChar;
+
+ // if this is the first character
+ if (mode == CHAR_MODE.FIRST) {
+ const {
+ width: borderWidth,
+ height: borderHeight
+ } = boxChar.outterSize;
+
+ // black border background
+ const rotateX = drawOffset + borderWidth / 2,
+ rotateY = pendding + borderHeight / 2;
+
+ rotateCanvas(ctx, angle - 5, rotateX, rotateY);
+ ctx.fillStyle = COLORS.BLACK;
+ ctx.fillRect(drawOffset, (canvasHeight - borderHeight) / 2, borderWidth, borderHeight);
+
+ // red background
+ rotateCanvas(ctx, angle + 3, rotateX, rotateY);
+ const bgScale = 0.85;
+ const bgWidth = borderWidth * bgScale,
+ bgHeight = borderHeight * bgScale;
+ const bgLeft = drawOffset + (borderWidth - bgWidth) / 2,
+ bgTop = (canvasHeight - bgHeight) / 2;
+ ctx.fillStyle = COLORS.RED;
+ ctx.fillRect(bgLeft, bgTop, bgWidth, bgHeight);
+
+ // first character
+ rotateCanvas(ctx, angle + 2, rotateX, rotateY);
+ const textLeft = drawOffset + (borderWidth - width) / 2 - left,
+ textTop = (canvasHeight - height) / 2 - top;
+ ctx.fillStyle = color;
+ ctx.font = boxChar.font;
+ ctx.fillText(char, textLeft, textTop);
+
+ drawOffset += boxChar.outterSize.width + gutter;
+ }
+
+ else {
+ // normal characters
+ const {
+ width: bgWidth,
+ height: bgHeight
+ } = boxChar.outterSize;
+
+ const rotateX = drawOffset + bgWidth / 2,
+ rotateY = pendding + bgHeight / 2;
+
+ rotateCanvas(ctx, angle + 1, rotateX, rotateY);
+ ctx.fillStyle = COLORS.BLACK;
+ ctx.fillRect(drawOffset, (canvasHeight - bgHeight) / 2, bgWidth, bgHeight);
+
+ const textLeft = drawOffset + (bgWidth - width) / 2 - left,
+ textTop = (canvasHeight - height) / 2 - top;
+ rotateCanvas(ctx, -1, rotateX, rotateY);
+ ctx.fillStyle = color;
+ ctx.font = boxChar.font;
+ ctx.fillText(char, textLeft, textTop);
+
+ drawOffset += boxChar.outterSize.width + gutter;
+ }
+
+ ctx.restore();
+
+ }
+
+ /* STROKE DRAWINGS */
+
+ const imageData = ctx.getImageData(0, 0, 1770, 1300);
+ const newImageData = ctx.createImageData(1770, 1300);
+
+ if (textStroke) {
+ const coreSize = parseInt(textStrokeWidth), start = Math.floor(coreSize / 2);
+ for (let i = start; i < imageData.height - start; ++i) {
+ for (let j = start; j < imageData.width - start; ++j) {
+ const index = i * imageData.width * 4 + j * 4;
+ if (!imageData.data[index + 3]) {
+ continue;
+ }
+
+ const a = imageData.data[index + 3];
+ for (let x = i - coreSize + 1; x < i + coreSize; ++x) {
+ for (let y = j - coreSize + 1; y < j + coreSize; ++y) {
+ const newIndex = x * imageData.width * 4 + y * 4;
+
+ // some kind of rgb color
+ newImageData.data[newIndex] = 255;
+ newImageData.data[newIndex + 1] = 255;
+ newImageData.data[newIndex + 2] = 255;
+ newImageData.data[newIndex + 3] += a / 4;
+ }
+ }
+ }
+ }
+ }
+
+ const {
+ canvas: borderCanvas,
+ context: borderCtx
+ } = letterCanvas(1770, 1300);
+
+ borderCtx.putImageData(newImageData, 0, 0);
+
+ ctx.save();
+ ctx.globalCompositeOperation = 'destination-over';
+ ctx.drawImage(borderCanvas, 0, 0);
+
+ ctx.restore();
+
+ return canvasHeight;
+ }
+}
\ No newline at end of file
diff --git a/scripts/textgen/utils.js b/scripts/textgen/utils.js
index 3886796..cfd8043 100644
--- a/scripts/textgen/utils.js
+++ b/scripts/textgen/utils.js
@@ -1 +1,78 @@
-function randomOper(){return Math.floor(10*Math.random())%2?1:-1}function rotateCanvas(t,e,n,a){t.translate(n,a),t.rotate(Math.PI*e/180),t.translate(-n,-a)}function letterCanvas(t,e){const n=document.createElement("canvas");n.width=t,n.height=e;const a=n.getContext("2d");if(a)return{canvas:n,context:a};console.error("Failed to generate text: failed to create canvas for the letter.")}function getCharSize(t,e,n="sans-serif",a="normal"){const{context:o}=letterCanvas(e,e);o.font=`${a} ${e}px ${n}`,o.textBaseline="top",o.fillText(t,0,0);let r=0,l=-1,c=e,s=-1,i=e;const f=o.getImageData(0,0,e,e).data;for(let t=0;th2{text-align:center}select{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none}textarea{font-family:sans-serif;box-sizing:border-box;width:100%;height:80%;font-size:32px;text-align:center;resize:none;white-space:pre-wrap}textarea>*{display:table-cell;vertical-align:middle}input[type=number]{max-width:60px}input:disabled{cursor:not-allowed;opacity:.5}#editor{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr;grid-template-areas:"content options";grid-gap:30px;color:#000;padding:0 20px;height:100%;border-radius:10px}#editor>div>h2{text-align:center}@media screen and (max-width:767px),screen and (max-device-width:767px){#editor{grid-template-columns:1fr;grid-template-areas:"content" "options"}}#editor>div>*{margin:10px}.options-tab{display:none}textarea{transform:rotate(-.42deg)}.checkmark{transform:rotate(-5deg)}input[type=number]{transform:rotate(3deg)}.cb-container{display:block;position:relative;padding-left:35px;margin-bottom:12px;cursor:pointer}.cb-container input{position:absolute;opacity:0;cursor:pointer;height:16px;width:16px;top:0;left:0;z-index:1}.checkmark{position:absolute;top:0;left:0;height:16px;width:16px;background-color:#fff;border:2px solid #000;box-shadow:4px 4px #000;color:#000}.checkmark:after{content:"";position:absolute;display:none}.cb-container input:checked~.checkmark:after{display:block}.cb-container .checkmark:after{left:4px;top:0;width:5px;height:10px;border:solid #000;border-width:0 3px 3px 0;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}
+/* General */
+input, textarea, button, select {
+ background-color: white;
+ border: 2px solid black;
+ border-radius: 0;
+ box-shadow: 4px 4px black;
+ color: black;
+ padding: 5px;
+ outline: none;
+}
+
+.options-tab>h2 {
+ text-align: center;
+}
+
+select {
+ box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+}
+
+textarea {
+ font-family: sans-serif;
+ box-sizing: border-box;
+ width: 100%;
+ height: 80%;
+ font-size: 32px;
+ text-align: center;
+ resize: none;
+ white-space: pre-wrap;
+}
+
+textarea > * {
+ display: table-cell;
+ vertical-align: middle;
+}
+
+input[type="number"] {
+ max-width: 60px;
+}
+
+input:disabled {
+ cursor: not-allowed;
+ opacity: .5;
+}
+
+/* Editors */
+#editor {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-template-rows: 1fr;
+ grid-template-areas: "content options";
+ grid-gap: 30px;
+ color: black;
+ padding: 0 20px;
+ height: 100%;
+ border-radius: 10px;
+}
+
+#editor > div > h2 {
+ text-align: center;
+}
+
+@media screen and (max-width:767px),
+screen and (max-device-width:767px) {
+ #editor {
+ grid-template-columns: 1fr;
+ grid-template-areas: "content" "options";
+ }
+}
+
+#editor > div > * {
+ margin: 10px;
+}
+
+/* Tab options */
+.options-tab {
+ display: none;
+}
+
+/* Rotation decorations */
+textarea {
+ transform: rotate(-.42deg);
+}
+
+.checkmark {
+ transform: rotate(-5deg);
+}
+
+input[type=number] {
+ transform: rotate(3deg);
+}
+
+/* checkbox */
+.cb-container {
+ display: block;
+ position: relative;
+ padding-left: 35px;
+ margin-bottom: 12px;
+ cursor: pointer;
+}
+
+.cb-container input {
+ position: absolute;
+ opacity: 0;
+ cursor: pointer;
+ height: 16px;
+ width: 16px;
+ top: 0;
+ left: 0;
+ z-index: 1;
+}
+
+.checkmark {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 16px;
+ width: 16px;
+ background-color: white;
+ border: 2px solid black;
+ box-shadow: 4px 4px black;
+ color: black;
+}
+
+.checkmark:after {
+ content: "";
+ position: absolute;
+ display: none;
+}
+
+.cb-container input:checked ~ .checkmark:after {
+ display: block;
+}
+
+.cb-container .checkmark:after {
+ left: 4px;
+ top: 0;
+ width: 5px;
+ height: 10px;
+ border: solid black;
+ border-width: 0 3px 3px 0;
+ -webkit-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ transform: rotate(45deg);
+}
diff --git a/styles/main.css b/styles/main.css
index aa58227..06aa2ce 100644
--- a/styles/main.css
+++ b/styles/main.css
@@ -171,4 +171,4 @@ screen and (max-device-width:767px) {
position: relative;
transform: translate(5%, 5%);
}
-}
+}
\ No newline at end of file
diff --git a/version.js b/version.js
index ef73b78..1acd329 100644
--- a/version.js
+++ b/version.js
@@ -16,3 +16,5 @@ if (VCBOOL === false || VCINFO !== VERSION) {
document.getElementById('notice-bg').style.display = 'none';
});
}
+
+
From 526596f90b71e5b26d73564b1c8a5a7ed44b5cfe Mon Sep 17 00:00:00 2001
From: sora <34794115+skyventuree@users.noreply.github.com>
Date: Thu, 5 May 2022 22:10:51 +0700
Subject: [PATCH 3/3] add fallback
---
styles/main.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/styles/main.css b/styles/main.css
index 06aa2ce..199da08 100644
--- a/styles/main.css
+++ b/styles/main.css
@@ -18,9 +18,9 @@ body {
body {
height: 100%;
font-size: 18px;
- background-color: #FF0405;
overflow-x: hidden;
background: url("../assets/background.jpg") no-repeat center center fixed;
+ background-color: #FF0405; /* fallback */
}
body, div {