Open files from your terminal
d3codex is a small, open shell script that opens any local D3 / PickBASIC
file in the Annotator, full-screen, straight from your terminal. It
encodes the file into the page URL and opens your browser. Nothing is uploaded: the
source rides in the URL fragment, which the page reads back in the browser.
Install
One line. The installer downloads the script to ~/.local/bin and adds
that dir to your PATH if it is not already there (no sudo, nothing outside your home).
View the installer.
curl -fsSL https://d3codex.com/install.sh | bash
Prefer to do it by hand? Save the script into a directory already on your
PATH (e.g. ~/.local/bin) and make it executable:
curl -fsSL https://d3codex.com/d3codex.sh -o ~/.local/bin/d3codex && chmod +x ~/.local/bin/d3codex
Use it
d3codex myprogram.bp- Open a file in the Annotator, full-screen Focus mode.
cat prog.bp | d3codex -- Read the program from stdin.
d3codex --split prog.bp- Open the split edit + preview view instead of Focus.
d3codex -p prog.bp- Print the URL instead of opening it (useful headless / over SSH).
D3CODEX_ORIGIN=http://localhost:7101 d3codex prog.bp- Point at a local D3Codex build.
d3codex --help lists every option.
How it works
The script builds the Annotator URL and opens it. The source is carried in the URL
hash (after #), so it never leaves your machine for a server:
#s=<base64url>- your file's bytes, base64url-encoded.#z=<base64url>- a zlib-DEFLATE'd form, used automatically when it is shorter (big files).&focus=1- opens the full-screen Focus view (drop it, or use--split, for the split view).
This is the same hash scheme the Annotator's own Share menu produces, so the script and the site stay in lock-step.
Requirements
Only standard tools: bash, base64, tr,
mktemp. Compression (#z=) uses python3 or node if
present; without either it simply uses the uncompressed form. Supported on
macOS and Linux (and WSL on Windows). On native Windows the opener step differs: the
script falls back to printing the URL for you to open.
The script
Read it before you run it. This is the exact file served at /d3codex.sh.
#!/usr/bin/env bash
# d3codex - open a local file in the D3Codex web Annotator, full-screen.
#
# d3codex myprogram.bp
#
# Source / latest version: https://d3codex.com/d3codex.sh
# Annotator: https://d3codex.com/tools/annotate/
#
# How it works (and a reference example for the D3Codex hash scheme): the source
# is carried in the URL fragment, so nothing is uploaded - the page reads it back
# in the browser. The Annotator (https://d3codex.com/tools/annotate/) accepts:
# #s=<X> X = base64url (no padding) of the file's UTF-8 bytes.
# #z=<X> X = base64url of a zlib DEFLATE stream of the bytes (used when shorter).
# &focus=1 opens full-screen Focus mode.
# This script builds both forms, picks the shorter, and opens it in the browser.
#
# Supported on macOS and Linux (and WSL on Windows). On native Windows the opener
# step differs - the script falls back to printing the URL for you to open, or adapt
# opener() to your browser; everything else is portable.
set -euo pipefail
ORIGIN="${D3CODEX_ORIGIN:-https://d3codex.com}" # override for local dev, e.g. http://localhost:7101
FOCUS="&focus=1"
PRINT_ONLY=0
usage() {
cat <<'EOF'
d3codex - open a file in the D3Codex Annotator (full-screen Focus mode).
d3codex FILE open FILE in the annotator
d3codex - read the program from stdin
d3codex -p FILE print the URL instead of opening it
d3codex --split FILE open in split (edit + preview) view, not Focus
The source is carried in the URL hash; nothing is uploaded.
Override the site with D3CODEX_ORIGIN (e.g. http://localhost:7101).
EOF
}
while [ "$#" -gt 0 ]; do
case "$1" in
-p|--print) PRINT_ONLY=1; shift ;;
--split) FOCUS=""; shift ;;
-h|--help) usage; exit 0 ;;
--) shift; break ;;
-) break ;; # explicit stdin sentinel
-*) echo "d3codex: unknown option: $1" >&2; exit 2 ;;
*) break ;;
esac
done
# base64url, no padding. The tr also unwraps base64's 76-column line breaks, so the
# output is identical on macOS (BSD base64) and Linux (GNU coreutils).
b64url() { base64 | tr '+/' '-_' | tr -d '=\n'; }
# zlib-format DEFLATE (RFC 1950), matching the site's CompressionStream('deflate'),
# which DecompressionStream('deflate') inflates regardless of compressor or level.
# Returns non-zero if neither python3 nor node is available.
deflate() {
if command -v python3 >/dev/null 2>&1; then
python3 -c 'import sys,zlib; sys.stdout.buffer.write(zlib.compress(sys.stdin.buffer.read(),9))'
elif command -v node >/dev/null 2>&1; then
node -e 'const z=require("zlib"),c=[];process.stdin.on("data",d=>c.push(d)).on("end",()=>process.stdout.write(z.deflateSync(Buffer.concat(c),{level:9})))'
else
return 1
fi
}
# Open a URL in the default browser, or print it if no opener exists.
opener() {
if command -v open >/dev/null 2>&1; then open "$1"
elif command -v xdg-open >/dev/null 2>&1; then xdg-open "$1"
elif command -v wslview >/dev/null 2>&1; then wslview "$1"
else echo "d3codex: no opener found; URL is:" >&2; printf '%s\n' "$1"
fi
}
# Resolve the source to a file. Buffer stdin to a temp file so it can be read
# twice (once raw, once compressed); clean it up on exit.
FILE="${1:-}"
TMP=""
trap '[ -n "$TMP" ] && rm -f "$TMP"' EXIT
if [ -z "$FILE" ] || [ "$FILE" = "-" ]; then
TMP="$(mktemp "${TMPDIR:-/tmp}/d3codex.XXXXXX")"
cat > "$TMP"
SRCFILE="$TMP"; LABEL="stdin"
else
[ -f "$FILE" ] || { echo "d3codex: no such file: $FILE" >&2; exit 1; }
SRCFILE="$FILE"; LABEL="$FILE"
fi
[ -s "$SRCFILE" ] || { echo "d3codex: nothing to open (empty input)" >&2; exit 1; }
# Build the raw #s= link; switch to the compressed #z= link only if a deflater is
# present, exited cleanly, and produced a genuinely shorter fragment.
RAW="$(b64url < "$SRCFILE")"
KEY=s; FRAG="$RAW"
if Z="$(deflate < "$SRCFILE" 2>/dev/null | b64url)"; then
[ -n "$Z" ] && [ "${#Z}" -lt "${#RAW}" ] && { KEY=z; FRAG="$Z"; }
fi
URL="${ORIGIN}/tools/annotate/#${KEY}=${FRAG}${FOCUS}"
# Very long programs can exceed the command-line length (ARG_MAX, passing the URL to
# the opener) or the browser's address-bar limit; warn but still try.
[ "${#URL}" -gt 100000 ] &&
echo "d3codex: warning: large input; the URL may exceed the browser or command-line limit" >&2
if [ "$PRINT_ONLY" -eq 1 ]; then
printf '%s\n' "$URL"
else
printf 'Opening %s in the D3Codex Annotator...\n' "$LABEL"
opener "$URL"
fi