diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..672ad48
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,41 @@
+# Secrets
+/**/**/.env
+/**/**/origin.server
+/**/**/server.manifest
+/**/**/server.registry
+/**/**/*.secret.*
+
+/**/**/_shared
+
+# Trash
+/**/**/*.log
+/**/**/dumps.log
+/**/**/.crash.log
+/**/**/.tmp
+/**/**/.cache
+/**/**/cache
+/**/**/out
+/**/**/.out
+/**/**/dist
+/**/**/node_modules
+/**/**/corenode_modules
+/**/**/.DS_Store
+/**/**/package-lock.json
+/**/**/yarn.lock
+/**/**/.evite
+/**/**/build
+/**/**/uploads
+/**/**/d_data
+/**/**/*.tar
+/**/**/*.7z
+/**/**/*.zip
+/**/**/*.env
+
+# Logs
+/**/**/npm-debug.log*
+/**/**/yarn-error.log
+/**/**/dumps.log
+/**/**/corenode.log
+
+# Temporal configurations
+/**/**/.aliaser
diff --git a/node_api/api/index.js b/node_api/api/index.js
new file mode 100644
index 0000000..f5618a1
--- /dev/null
+++ b/node_api/api/index.js
@@ -0,0 +1,40 @@
+require('dotenv').config()
+
+const express = require("express")
+const cors = require("cors")
+const mlib = require("../../node_lib")
+
+let app = null
+
+const { LISTENING_PORT } = process.env
+const PORT = LISTENING_PORT || 3000
+
+async function main() {
+ app = express()
+
+ app.use(cors())
+ app.use(express.json())
+
+ app.get("/api", async (req, res) => {
+ let { random } = req.query
+
+ // try to parse random, can be a number or a boolean
+ if (random) {
+ if (random === "true") {
+ random = true
+ } else if (Number(random)) {
+ random = Number(random)
+ }
+ }
+
+ const phrases = await mlib({ random })
+
+ res.json(phrases)
+ })
+
+ app.listen(PORT)
+
+ console.log(`Listening on port ${PORT}`)
+}
+
+main().catch(console.error)
\ No newline at end of file
diff --git a/node_api/package.json b/node_api/package.json
new file mode 100644
index 0000000..2f37dcd
--- /dev/null
+++ b/node_api/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "node_api",
+ "version": "1.0.0",
+ "main": "index.js",
+ "license": "MIT",
+ "dependencies": {
+ "dotenv": "^16.4.1",
+ "express": "^4.18.2"
+ }
+}
diff --git a/node_api/web/.eslintrc.cjs b/node_api/web/.eslintrc.cjs
new file mode 100644
index 0000000..4dcb439
--- /dev/null
+++ b/node_api/web/.eslintrc.cjs
@@ -0,0 +1,20 @@
+module.exports = {
+ root: true,
+ env: { browser: true, es2020: true },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:react/recommended',
+ 'plugin:react/jsx-runtime',
+ 'plugin:react-hooks/recommended',
+ ],
+ ignorePatterns: ['dist', '.eslintrc.cjs'],
+ parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
+ settings: { react: { version: '18.2' } },
+ plugins: ['react-refresh'],
+ rules: {
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ },
+}
diff --git a/node_api/web/.gitignore b/node_api/web/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/node_api/web/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/node_api/web/README.md b/node_api/web/README.md
new file mode 100644
index 0000000..f768e33
--- /dev/null
+++ b/node_api/web/README.md
@@ -0,0 +1,8 @@
+# React + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
diff --git a/node_api/web/index.html b/node_api/web/index.html
new file mode 100644
index 0000000..e7597ba
--- /dev/null
+++ b/node_api/web/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+ Monstercanker
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/node_api/web/package.json b/node_api/web/package.json
new file mode 100644
index 0000000..fddeb5d
--- /dev/null
+++ b/node_api/web/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "web",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "axios": "^1.6.7",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.2.43",
+ "@types/react-dom": "^18.2.17",
+ "@vitejs/plugin-react": "^4.2.1",
+ "eslint": "^8.55.0",
+ "eslint-plugin-react": "^7.33.2",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-react-refresh": "^0.4.5",
+ "vite": "^5.0.8"
+ }
+}
diff --git a/node_api/web/src/index.css b/node_api/web/src/index.css
new file mode 100644
index 0000000..e20a1c7
--- /dev/null
+++ b/node_api/web/src/index.css
@@ -0,0 +1,86 @@
+:root {
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme : light dark;
+ color : rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis : none;
+ text-rendering : optimizeLegibility;
+ -webkit-font-smoothing : antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+a {
+ font-weight : 500;
+ color : #646cff;
+ text-decoration: inherit;
+}
+
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ display : flex;
+ flex-direction: column;
+
+ margin : 0;
+ padding: 0;
+}
+
+h1 {
+ font-size : 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius : 8px;
+ border : 1px solid transparent;
+ padding : 0.6em 1.2em;
+ font-size : 1em;
+ font-weight : 500;
+ font-family : inherit;
+ background-color: #1a1a1a;
+ cursor : pointer;
+ transition : border-color 0.25s;
+}
+
+button:hover {
+ border-color: #646cff;
+}
+
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+.app {
+ display : flex;
+ flex-direction: column;
+
+ align-items : center;
+ justify-content: center;
+
+ width : 100%;
+ height: 100vh;
+}
+
+footer {
+ position: fixed;
+
+ bottom: 10vh;
+ left : 0;
+
+ width : 100%;
+ height: fit-content;
+
+ display: flex;
+
+ align-items : center;
+ justify-content: center;
+
+ gap: 20px;
+}
\ No newline at end of file
diff --git a/node_api/web/src/main.jsx b/node_api/web/src/main.jsx
new file mode 100644
index 0000000..8431b53
--- /dev/null
+++ b/node_api/web/src/main.jsx
@@ -0,0 +1,52 @@
+import React from "react"
+import ReactDOM from "react-dom/client"
+
+import axios from "axios"
+
+import "./index.css"
+
+const API_ENDPOINT = import.meta.env.PROD ? "/api" : `http://${window.location.hostname}:3000/api`
+
+const App = () => {
+ const [loading, setLoading] = React.useState(true)
+ const [randomWord, setRandomWord] = React.useState(null)
+
+ async function loadRandom({
+ random = true,
+ } = {}) {
+ setLoading(true)
+
+ let { data } = await axios({
+ url: API_ENDPOINT,
+ method: "GET",
+ params: {
+ random,
+ },
+ })
+
+ setLoading(false)
+
+ setRandomWord(data)
+ }
+
+ React.useEffect(() => {
+ loadRandom()
+ }, [])
+
+ return
+ {
+ loading ?
Loading...
:
{randomWord}
+ }
+
+
+
+}
+
+ReactDOM.createRoot(document.getElementById("root")).render(
+
+
+ ,
+)
diff --git a/node_api/web/vite.config.js b/node_api/web/vite.config.js
new file mode 100644
index 0000000..5a33944
--- /dev/null
+++ b/node_api/web/vite.config.js
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+})
diff --git a/node_lib/index.js b/node_lib/index.js
new file mode 100644
index 0000000..5fa0ece
--- /dev/null
+++ b/node_lib/index.js
@@ -0,0 +1,29 @@
+const raw_text = "https://git.ragestudio.net/srgooglo/monstercanker/raw/branch/main/main.txt"
+
+function randomSelect(array) {
+ return array[Math.floor(Math.random() * array.length)]
+}
+
+module.exports = async ({ random } = {}) => {
+ const response = await fetch(raw_text)
+
+ let phrases = await response.text()
+
+ phrases = phrases.split("\n")
+
+ if (random) {
+ if (typeof random === "number") {
+ const randomSelections = []
+
+ for await (const _ of Array(random)) {
+ randomSelections.push(randomSelect(phrases))
+ }
+
+ phrases = randomSelections
+ } else {
+ phrases = randomSelect(phrases)
+ }
+ }
+
+ return phrases
+}
diff --git a/node_lib/index.test.js b/node_lib/index.test.js
new file mode 100644
index 0000000..296c14a
--- /dev/null
+++ b/node_lib/index.test.js
@@ -0,0 +1,17 @@
+const index = require(".")
+
+async function main() {
+ console.log(`Output entire list...`)
+
+ console.log(await index())
+
+ console.log(`Output 1 random phrase...`)
+
+ console.log(await index({ random: true }))
+
+ console.log(`Output 3 random phrase...`)
+
+ console.log(await index({ random: 3 }))
+}
+
+main()
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..a1ada9b
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "cors": "^2.8.5"
+ }
+}