Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@

<p align="center">
<b>🌐 <a href="https://portal.dynamicweblab.com/">Online edition (beta)</a></b>: Play Together with friends, optional accounts &nbsp;·&nbsp;
<b>▶ <a href="https://dynamic-web-lab.github.io/MiniCrafter/">Free edition</a></b>: the whole game, offline, no account
<b>▶ <a href="https://dynamic-web-lab.github.io/MiniCrafter/">Free edition</a></b>: the whole game, offline, no account &nbsp;·&nbsp;
<b>✨ <a href="https://portal.dynamicweblab.com/features.html">All features</a></b>
</p>

<p align="center">
Expand Down
Binary file added docs/screenshots/course.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/photo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/together.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions features.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* Features page (builds on legal.css) */
.features { max-width: 1040px; }
.f-hero { text-align: center; }
.f-logo { border-radius: 22px; box-shadow: 0 6px 20px rgba(0, 0, 0, .45); }
.f-hero h1 { font-size: 2.6rem; margin-top: 10px; }
.f-tagline { max-width: 720px; margin: 10px auto; font-size: 1.1rem; }
.f-cta { margin: 18px 0; text-align: center; display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.f-btn { display: inline-block; padding: 12px 22px; border-radius: 10px; background: #3f7d2a; border: 2px solid #66b043; color: #fff; font-weight: 700; text-decoration: none; font-size: 1.1rem; }
.f-btn:hover { background: #4a9132; }
.f-btn.alt { background: #24324f; border-color: #3b82f6; }
.f-shot { width: 100%; height: auto; border-radius: 12px; margin-top: 10px; box-shadow: 0 10px 30px rgba(0, 0, 0, .4); }
.f-why li { margin: 8px 0; }
.f-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; }
.f-grid article { background: rgba(255, 255, 255, .04); border: 1px solid #2c3446; border-radius: 12px; overflow: hidden; }
.f-grid article img { width: 100%; height: auto; display: block; aspect-ratio: 16 / 9; object-fit: cover; }
.f-grid article h3 { margin: 12px 14px 4px; font-size: 1.05rem; color: #9be06a; }
.f-grid article p { margin: 0 14px 14px; font-size: .95rem; }
.f-grid .f-text { grid-column: 1 / -1; padding-bottom: 4px; }
#faq h3 { margin: 18px 0 4px; font-size: 1.05rem; color: #9be06a; }
#faq p { margin: 0; }
section { margin-top: 8px; }
193 changes: 193 additions & 0 deletions features.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ <h1>MiniCrafter</h1>
</details>
<p class="note touch-only">Touch: left stick walks, drag to look, tap to place or flip, hold to mine or attack. Holding a bow or shield? Hold to draw or block.</p>
<p class="note">Your world is saved automatically in this browser. <span id="offline-note"></span> <span id="game-version"></span></p>
<p class="note legal-links"><a href="privacy.html" target="_blank" rel="noopener">Privacy Policy</a> · <a href="terms.html" target="_blank" rel="noopener">Terms of Use</a></p>
<p class="note legal-links"><a href="features.html" target="_blank" rel="noopener">✨ All features</a> · <a href="privacy.html" target="_blank" rel="noopener">Privacy Policy</a> · <a href="terms.html" target="_blank" rel="noopener">Terms of Use</a></p>
</div>
</div>
</div>
Expand Down
24 changes: 24 additions & 0 deletions llms.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# MiniCrafter

> MiniCrafter is a free, kid-safe block-building game that runs in any web browser (computers, Chromebooks, tablets and phones) with no install, no ads and no tracking. Players build worlds, make their own obstacle-course games, learn to code with a robot called Bit, raise animals and play together with friends using emoji only. It is an original open-source game (MIT License) by Dynamic Web Lab FZE LLC, not affiliated with Minecraft or Mojang.

Key facts:
- Price: free. No ads, no in-game purchases, no subscriptions.
- Ages: Creative and gentle Survival suit children from about 6; an optional Adventure mode (monsters, combat, hunger, Hardcore) for teens and grown-ups sits behind a grown-up check.
- Safety: no text chat; Play Together uses picked names (like "Blue Fox") and emoji; the host lets each player in; players connect through a relay, never directly.
- Accounts: optional; only a made-up username and a password (no email); players under 13 need a parent or guardian; accounts can be deleted any time.
- Platforms: any modern browser; installable as an app; works offline.
- Multiplayer: Play Together, up to 4 players, in the online edition.
- Learning: 64 quests (counting, times tables, colours, shapes, coding) and Blockly coding for Bit the robot.

## Features
- [All features, with screenshots and FAQ](features.html): Course Maker, Play Together, Bit coding, Photo Mode, animals and pets, farming, fun blocks, villages, quests, Spark circuits, power tools, Adventure mode, tablets and phones
- [Play the game](./)

## Policies
- [Privacy Policy](privacy.html): what is kept (a private username, a password hash, 30-day sessions, a consent record), what is not, and how to delete an account
- [Terms of Use](terms.html)

## Project
- [Source code on GitHub](https://github.com/Dynamic-Web-Lab/MiniCrafter)
- Contact: info@dynamicweblab.com
2 changes: 1 addition & 1 deletion server/dev.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { attachRelay } from './rooms.mjs';

const ROOT = fileURLToPath(new URL('..', import.meta.url));
const TYPES = { '.html': 'text/html', '.js': 'text/javascript', '.mjs': 'text/javascript', '.css': 'text/css', '.json': 'application/json', '.webmanifest': 'application/manifest+json', '.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml' };
const SERVE = ['index.html', 'style.css', 'privacy.html', 'terms.html', 'legal.css', 'sw.js', 'manifest.webmanifest', 'icons', 'src', 'vendor'];
const SERVE = ['index.html', 'style.css', 'privacy.html', 'terms.html', 'legal.css', 'features.html', 'features.css', 'llms.txt', 'docs', 'sw.js', 'manifest.webmanifest', 'icons', 'src', 'vendor'];

/** Starts the dev server. Returns { server, port, url }. */
export async function startDevServer(port = 8770) {
Expand Down
4 changes: 2 additions & 2 deletions sw.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Service worker: caches the whole game so it works offline once loaded.
// Bump VERSION whenever files change so players get the update.
const VERSION = 'minicrafter-v26';
const VERSION = 'minicrafter-v27';
const CORE = [
'./', './index.html', './style.css', './privacy.html', './terms.html', './legal.css', './manifest.webmanifest', './site-config.json',
'./', './index.html', './style.css', './privacy.html', './terms.html', './legal.css', './features.html', './features.css', './manifest.webmanifest', './site-config.json',
'./icons/icon-192.png', './icons/icon-512.png', './icons/icon-maskable-512.png', './icons/apple-touch-icon.png', './icons/favicon-32.png',
'./vendor/three.module.js', './vendor/blockly.min.js', './vendor/media/sprites.png',
'./src/adventure.js',
Expand Down
60 changes: 46 additions & 14 deletions tools/deploy-site.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,55 @@
#!/usr/bin/env bash
# Deploys the current checkout to our hosted MiniCrafter site (the online edition with
# Play Together; accounts later). Where it goes lives in tools/.deploy.env, which is not in Git:
# Deploys the current checkout to our hosted MiniCrafter site (the online edition: Play Together
# and accounts). Where it goes lives in tools/.deploy.env, which is not in Git:
# DEPLOY_SSH=my-server-alias
# DEPLOY_DIR=/var/www/minicrafter-site
# SITE_URL=https://example.com/ (only used for the message at the end)
# The repo's site-config.json keeps the online features off (the free copy); this script
# uploads an "on" version to our site instead.
# SITE_URL=https://example.com/ (the site's public address, with a trailing slash)
# It builds the site in a temporary folder (your checkout is never changed), then:
# - uploads an "on" site-config.json (the copy in Git keeps the online features off),
# - adds the site's address to features.html (canonical and social-sharing tags),
# - writes sitemap.xml and robots.txt for search engines.
set -euo pipefail
cd "$(dirname "$0")/.."
[ -f tools/.deploy.env ] || { echo "Create tools/.deploy.env first (see the top of this script)"; exit 1; }
# shellcheck disable=SC1091
source tools/.deploy.env
: "${DEPLOY_SSH:?}" "${DEPLOY_DIR:?}"
cp site-config.json "${TMPDIR:-/tmp}/site-config.json.keep" 2>/dev/null || true
printf '{ "online": true, "rooms": "/rooms", "accounts": true }\n' > site-config.json
trap 'mv -f "${TMPDIR:-/tmp}/site-config.json.keep" site-config.json 2>/dev/null || true' EXIT
rsync -az --delete \
--include='index.html' --include='style.css' --include='privacy.html' --include='terms.html' --include='legal.css' --include='sw.js' --include='manifest.webmanifest' --include='site-config.json' \
--include='icons/***' --include='src/***' --include='vendor/***' --exclude='*' \
./ "$DEPLOY_SSH:$DEPLOY_DIR/"
: "${DEPLOY_SSH:?}" "${DEPLOY_DIR:?}" "${SITE_URL:?set SITE_URL in tools/.deploy.env}"
case "$SITE_URL" in */) ;; *) SITE_URL="$SITE_URL/" ;; esac

BUILD=$(mktemp -d "${TMPDIR:-/tmp}/minicrafter-site.XXXXXX")
trap 'rm -rf "$BUILD"' EXIT
rsync -a \
--include='index.html' --include='style.css' --include='sw.js' --include='manifest.webmanifest' \
--include='privacy.html' --include='terms.html' --include='legal.css' \
--include='features.html' --include='features.css' --include='llms.txt' \
--include='icons/***' --include='src/***' --include='vendor/***' \
--include='docs/' --include='docs/screenshots/***' --exclude='*' \
./ "$BUILD/"

printf '{ "online": true, "rooms": "/rooms", "accounts": true }\n' > "$BUILD/site-config.json"

# Site-specific tags on the features page (absolute addresses for search engines and link previews).
META="<link rel=\"canonical\" href=\"${SITE_URL}features.html\">\n <meta property=\"og:url\" content=\"${SITE_URL}features.html\">\n <meta property=\"og:image\" content=\"${SITE_URL}docs/screenshots/course.jpg\">\n <meta name=\"twitter:image\" content=\"${SITE_URL}docs/screenshots/course.jpg\">"
python3 - "$BUILD/features.html" "$META" <<'PY'
import sys
p, meta = sys.argv[1], sys.argv[2].replace('\\n', '\n')
s = open(p).read()
assert '<!--SITE-META-->' in s
open(p, 'w').write(s.replace('<!--SITE-META-->', meta, 1))
PY

TODAY=$(date +%Y-%m-%d)
cat > "$BUILD/sitemap.xml" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>${SITE_URL}</loc><lastmod>${TODAY}</lastmod><priority>1.0</priority></url>
<url><loc>${SITE_URL}features.html</loc><lastmod>${TODAY}</lastmod><priority>0.9</priority></url>
<url><loc>${SITE_URL}privacy.html</loc><lastmod>${TODAY}</lastmod><priority>0.3</priority></url>
<url><loc>${SITE_URL}terms.html</loc><lastmod>${TODAY}</lastmod><priority>0.3</priority></url>
</urlset>
EOF
printf 'User-agent: *\nAllow: /\nDisallow: /api/\nDisallow: /rooms\nSitemap: %ssitemap.xml\n' "$SITE_URL" > "$BUILD/robots.txt"

rsync -az --delete "$BUILD/" "$DEPLOY_SSH:$DEPLOY_DIR/"
ssh "$DEPLOY_SSH" "chmod -R a+rX $DEPLOY_DIR"
echo "Deployed $(git rev-parse --short HEAD) to ${SITE_URL:-$DEPLOY_SSH:$DEPLOY_DIR}"
echo "Deployed $(git rev-parse --short HEAD)$(git diff --quiet HEAD -- . 2>/dev/null || echo ' (+ uncommitted changes)') to $SITE_URL"
Loading