diff --git a/out/changelog.cjs b/out/changelog.cjs
new file mode 100755
index 00000000..ce0f2c72
--- /dev/null
+++ b/out/changelog.cjs
@@ -0,0 +1,85 @@
+#!/usr/bin/env node
+
+const fs = require('fs');
+const {execSync} = require("child_process");
+const {marked} = require("marked");
+const {emojify} = require("node-emoji");
+
+function getLogsByDate() {
+ const logs = execSync(`git log --date=short`).toString();
+ const commits = [];
+ for (let log of logs.split(/[a-zA-Z0-9]{40}/)) {
+ log = log.split('Date: ')[1];
+ if (!log) {
+ continue;
+ }
+ const obj = {
+ date: log.split('\n\n ')[0],
+ subject: log.split('\n\n ')[1].split('\n\ncommit ')[0]
+ }
+ commits.push(obj);
+ }
+
+ const dates = {};
+ for (const com of commits) {
+ if (!dates[com.date]) {
+ dates[com.date] = [];
+ }
+ dates[com.date].push(com);
+ }
+ return dates;
+}
+
+(async () => {
+ try {
+ const logs = getLogsByDate();
+
+ let html = "";
+ for (const [date, commit] of Object.entries(logs)) {
+ let lis = '';
+ for (const com of commit) {
+ let sub = com.subject.trim();
+ sub = emojify(sub);
+ sub = marked(sub, {mangle: false, headerIds: false});
+ sub = sub.replaceAll('\n', '
');
+ sub = sub.replaceAll('\t', ' - ');
+ if (sub.length < 30) {
+ continue;
+ }
+ lis += `