commit f1c2cc2a2440d2362bad21171d470bbde233223c Author: z8tek Date: Thu Jul 16 15:20:10 2026 +0400 Add Gematria mode 10 (v1.3.0) Port gematria logic from gematria.py: Hebrew/Arabic/English letter values with --lang flag (hebrew|arabic|english|all). Added to both bin/zitsbit and distributed zitsbit.js. Version bumped to 1.3.0. Co-authored-by: CommandCodeBot diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..40bfdd5 --- /dev/null +++ b/install.sh @@ -0,0 +1,44 @@ +#!/bin/sh +set -e + +BIN_DIR="${HOME}/bin" +SCRIPT_URL="https://app.z8tek.net/zitsbit/zitsbit.js" +TARGET="${BIN_DIR}/zitsbit" + +echo ">>> Installing zitsbit..." + +# Ensure ~/bin exists +mkdir -p "${BIN_DIR}" + +# Download the script +echo ">>> Downloading from ${SCRIPT_URL}..." +if command -v curl >/dev/null 2>&1; then + curl -sfL "${SCRIPT_URL}" -o "${TARGET}" +elif command -v wget >/dev/null 2>&1; then + wget -q "${SCRIPT_URL}" -O "${TARGET}" +else + echo "ERROR: Need curl or wget to install." >&2 + exit 1 +fi + +chmod +x "${TARGET}" + +# Add ~/bin to PATH if not already there +case ":${PATH}:" in + *:"${BIN_DIR}":*) ;; + *) + SHELL_PROFILE="${HOME}/.profile" + if [ -n "${ZSH_VERSION}" ]; then SHELL_PROFILE="${HOME}/.zshrc"; fi + if [ -n "${BASH_VERSION}" ]; then + [ -f "${HOME}/.bashrc" ] && SHELL_PROFILE="${HOME}/.bashrc" + fi + echo "export PATH=\"\${PATH}:${BIN_DIR}\"" >> "${SHELL_PROFILE}" + echo ">>> Added ${BIN_DIR} to PATH in ${SHELL_PROFILE}" + echo ">>> Run: source ${SHELL_PROFILE}" + ;; +esac + +echo "" +echo " zitsbit installed to ${TARGET}" +echo " Run: zitsbit --help" +echo "" diff --git a/version b/version new file mode 100644 index 0000000..f0bb29e --- /dev/null +++ b/version @@ -0,0 +1 @@ +1.3.0 diff --git a/zitsbit.js b/zitsbit.js new file mode 100755 index 0000000..de2bb37 --- /dev/null +++ b/zitsbit.js @@ -0,0 +1,450 @@ +#!/usr/bin/env node + +// ── Zitsbit mapping (conditional on next digit) ─────────────────── +const ZITSBIT_MAP = { + '1': nd => nd > 5 ? '7' : '4', + '2': () => '5', '3': () => '8', + '4': nd => nd > 5 ? '7' : '1', + '5': () => '2', '6': () => '9', + '7': nd => nd > 5 ? '1' : '4', + '8': () => '3', '9': () => '6', + '0': () => '0', +}; + +// ── Static mirror (no conditional) ─────────────────────────────── +function mirrorDigit(d) { + const map = { '0':'0','1':'1','2':'5','3':'Ɛ','4':'4','5':'2','6':'9','7':'7','8':'8','9':'6' }; + return map[d] || d; +} +function mirrorString(s) { + return s.split('').map(c => mirrorDigit(c)).reverse().join(''); +} + +// ── Glyph mapping (symbolic digit glyphs) ─────────────────────── +const GLYPH_MAP = { '0':'Ø','1':'ᛁ','2':'Ƨ','3':'Ɛ','4':'ᔭ','5':'Ƽ','6':'9','7':'ᒣ','8':'∞','9':'6' }; +function applyGlyphs(s) { + return [...s].map(c => GLYPH_MAP[c] || c).join(''); +} + +// ── Zero rules (pair-based, matches z8tek.net) ─────────────────── +function applyZeroTail(digits) { + if (digits.length < 2 || digits[digits.length-1] !== '0') return digits; + const pair = parseInt(digits[digits.length-2] + digits[digits.length-1], 10); + const result = (pair - 1).toString().padStart(2, '0'); + const d = [...digits]; + d[d.length-2] = result[0]; + d[d.length-1] = result[1]; + return d; +} + +function applyZeroMiddle(digits) { + let result = [...digits]; + let i = 0; + while (i < result.length) { + if (result[i] === '0' && i > 0) { + const pair = parseInt(result[i-1] + result[i], 10); + const pairStr = (pair - 1).toString().padStart(2, '0'); + const swapped = pairStr[1] + pairStr[0]; + result[i-1] = swapped[0]; + result[i] = swapped[1]; + result[i-1] = ''; + result = result.filter(x => x !== ''); + } + i++; + } + return result; +} + +function processZeros(str) { + let digits = [...str]; + digits = applyZeroTail(digits); + digits = applyZeroMiddle(digits); + return digits.join(''); +} + +// ── Zitsbit transform (passes letters through, maps digits) ───── +function zitsbitTransform(s) { + const chars = [...s]; + // Find next digit for each position + const nextDigit = (i) => { + for (let j = i + 1; j < chars.length; j++) { + if (/\d/.test(chars[j])) return parseInt(chars[j], 10); + } + return 0; + }; + return chars.map((c, i) => { + if (!/\d/.test(c)) return c; + if (c === '0') return '0'; + return ZITSBIT_MAP[c](nextDigit(i)); + }).join(''); +} + +// ── Solar cycle (digit phase mapping) ──────────────────────────── +function solarCycle(input) { + const steps = [`Input: ${input}`]; + const digits = [...input].filter(c => /\d/.test(c)).map(Number); + const phases = []; + for (const d of digits) { + const deg = (d / 9) * 202.5; + let label; + if (deg < 90) label = 'Growth (0-90°)'; + else if (deg < 180) label = 'Mirror (90-180°)'; + else if (deg < 270) label = 'Infinity (180-270°)'; + else label = 'Unity/Return (270-360°)'; + phases.push({ digit: d, degrees: deg.toFixed(1), phase: label }); + steps.push(` ${d} → ${deg.toFixed(1)}° → ${label}`); + } + return { result: digits.map(d => ((d/9)*202.5).toFixed(0) + '°').join(' '), steps, phases }; +} + +// ── Retrograde (each digit -1) ─────────────────────────────────── +function retrograde(input) { + const steps = [`Input: ${input}`]; + const result = [...input].map(c => { + if (/\d/.test(c)) { + const r = (parseInt(c, 10) - 1 + 10) % 10; + steps.push(` ${c} → ${r}`); + return String(r); + } + if (/[a-z]/.test(c)) { + const r = String.fromCharCode(((c.charCodeAt(0) - 97 - 1 + 26) % 26) + 97); + steps.push(` ${c} → ${r}`); + return r; + } + if (/[A-Z]/.test(c)) { + const r = String.fromCharCode(((c.charCodeAt(0) - 65 - 1 + 26) % 26) + 65); + steps.push(` ${c} → ${r}`); + return r; + } + return c; + }).join(''); + return { result, steps }; +} + +// ── Block Cycle (rotate-left N → static map → detect cycle) ───── +const BLOCK_MAP = { '0':'3','1':'3','2':'4','3':'2','4':'1','5':'5','6':'6','7':'7','8':'3','9':'6' }; + +function blockCycle(input, shift = 3, alignTo) { + const steps = [`Input: ${input}`, '', ' Step Value']; + const sep = ' ──── ─────────'; + steps.push(sep); + const seen = {}; + let state = String(input); + const block = []; + let iter = 1; + while (iter <= 21) { + if (state in seen) { + const first = seen[state]; + const cycle = block.slice(first); + steps.push(` It${String(iter).padEnd(4)} ${state} ← cycle`); + steps.push(''); + steps.push(` ✓ Cycle ${cycle.length} (starts at step ${first+1}):`); + steps.push(` ${cycle.join(' → ')}`); + return { result: cycle.join(' → '), steps, iterations: iter, cycleLen: cycle.length }; + } + seen[state] = block.length; + block.push(state); + steps.push(` It${String(iter).padEnd(4)} ${state}`); + let rotated; + if (alignTo && iter === 1) { + const idx = state.indexOf(alignTo); + if (idx > 0) { + rotated = state[idx] + state[idx-1] + state.slice(0, idx-1) + state.slice(idx+1); + } else if (idx === 0) { + rotated = state; + } else { + rotated = state; + } + } else { + rotated = state.slice(shift) + state.slice(0, shift); + } + state = [...rotated].map(c => BLOCK_MAP[c] || c).join(''); + iter++; + } + return { result: state, steps, iterations: iter-1 }; +} + +// ── Scenarios ──────────────────────────────────────────────────── +function scenario1(input, maxIter = 21) { + const parts = input.split('.'); + let left = parts[0], right = parts[1] || ''; + const seen = { [input]: 0 }, steps = []; steps.push(`Input: ${input}`, '', ' Step Value'); + const sep = ' ──── ─────────'; + steps.push(sep); + let iter = 1; + let usedFallback = false; + + while (iter <= maxIter) { + const revL = [...left].reverse().join(''), + revR = right ? [...right].reverse().join('') : ''; + let out = zitsbitTransform(revL) + (right ? '.'+zitsbitTransform(revR) : ''); + + // Fallback once: if rev→zb is seen, try zb-direct to break out of 2-cycle + if ((out in seen) && !usedFallback) { + const direct = zitsbitTransform(left) + (right ? '.'+zitsbitTransform(right) : ''); + if (!(direct in seen)) { + out = direct; + usedFallback = true; + } + } + + steps.push(` It${String(iter).padEnd(4)} ${out}`); + if (out in seen) { + const cycleStart = seen[out]; + const cycleLen = iter - cycleStart; + steps.push(''); + steps.push(` ✓ Cycle ${cycleLen} (starts at step ${cycleStart+1}): ${out}`); + return { result: out, steps, iterations: iter, cycleStart, cycleLen }; + } + seen[out] = iter; + left = out.split('.')[0]; right = out.includes('.') ? out.split('.')[1] : ''; + iter++; + } + return { result: left + (right ? '.'+right : ''), steps, iterations: iter-1 }; +} + +function scenario2(input, maxIter = 20) { + const parts = input.split('.'); + let left = parts[0], right = parts[1] || ''; + const seen = [], steps = []; steps.push(`Input: ${input}`); + let iter = 1; + while (iter <= maxIter) { + const mirL = mirrorString(left), + mirR = right ? mirrorString(right) : ''; + const zbL = zitsbitTransform(mirL), + zbR = right ? zitsbitTransform(mirR) : ''; + const revL = [...zbL].reverse().join(''), + revR = right ? [...zbR].reverse().join('') : ''; + const out = revL + (right ? '.'+revR : ''); + steps.push(` It${iter}: mirror(${mirL}${right ? '/'+mirR : ''}) → zitsbit(${zbL}${right ? '/'+zbR : ''}) → reverse(${out})`); + if (seen.slice(-2).includes(out)) { + steps.push(` ✓ Stable/2-cycle at iteration ${iter}: ${out}`); + return { result: out, steps, iterations: iter }; + } + seen.push(out); + left = out.split('.')[0]; + right = out.includes('.') ? out.split('.')[1] : ''; + iter++; + } + return { result: left + (right ? '.'+right : ''), steps, iterations: iter-1 }; +} + +function scenario3(input, _offset = 0) { + return solarCycle(input); +} + +function scenario6(input) { + return retrograde(input); +} + +function scenario7(input) { + const steps = [`Input: ${input}`]; + const mir = mirrorString(input); + steps.push(`Mirror: ${mir}`); + return { result: mir, steps }; +} + +function scenario8(input) { + const steps = [`Input: ${input}`]; + const rev = [...input].reverse().join(''); + steps.push(`Reversed: ${rev}`); + const mir = mirrorString(rev); + steps.push(`Mirror: ${mir}`); + return { result: mir, steps }; +} + +function scenario9(input) { + const steps = [`Input: ${input}`]; + const mir = mirrorString(input); + steps.push(`Mirror: ${mir}`); + const rev = [...mir].reverse().join(''); + steps.push(`Reversed: ${rev}`); + return { result: rev, steps }; +} + +// ── Rotation digit mapping (perspective number rule) ──────────── +// After orbit rotation, digits may need remapping based on their +// rotated readability. Same conditional pattern as zitsbit map. +const ROTATION_MAP = { + '0': () => '0', + '1': nd => nd > 5 ? '7' : '1', + '2': nd => nd > 5 ? '5' : '2', + '3': nd => nd > 5 ? '8' : '3', + '4': () => '4', + '5': nd => nd > 5 ? '2' : '5', + '6': () => '9', + '7': nd => nd > 5 ? '1' : '7', + '8': nd => nd > 5 ? '3' : '8', + '9': () => '6', +}; + +function applyRotationMap(str) { + const digits = [...str].filter(c => /\d/.test(c)); + return digits.map((d, i) => { + const nd = i + 1 < digits.length ? parseInt(digits[i+1], 10) : 0; + return ROTATION_MAP[d](nd); + }).join(''); +} + +// ── Orbit rotation (position shift only) ───────────────────────── +// Then applies rotation digit mapping. +function orbitTransform(str, angle) { + if (!angle) return null; // no perspective, skip + const steps = (angle / 90) % str.length; + if (!steps) return str; + const out = new Array(str.length); + [...str].forEach((c, i) => { out[(i + steps) % str.length] = c; }); + const shifted = out.join(''); + return applyRotationMap(shifted); +} + +// ── Reverse helper ─────────────────────────────────────────────── +function reverse(s) { return [...s].reverse().join(''); } + +// ── Gematria (letter → numeric value, multi-language) ────────── +const GEMATRIA_MAPS = { + hebrew: { + 'א':1,'ב':2,'ג':3,'ד':4,'ה':5,'ו':6,'ז':7,'ח':8,'ט':9, + 'י':10,'כ':20,'ך':20,'ל':30,'מ':40,'ם':40,'נ':50,'ן':50, + 'ס':60,'ע':70,'פ':80,'ף':80,'צ':90,'ץ':90,'ק':100,'ר':200, + 'ש':300,'ת':400, + }, + arabic: { + 'ا':1,'أ':1,'إ':1,'آ':1,'ب':2,'ج':3,'د':4,'ه':5,'ة':5, + 'و':6,'ز':7,'ح':8,'ط':9,'ي':10,'ى':10,'ك':20,'ل':30, + 'م':40,'ن':50,'س':60,'ع':70,'ف':80,'ص':90,'ق':100, + 'ر':200,'ش':300,'ت':400,'ث':500,'خ':600,'ذ':700,'ض':800, + 'ظ':900,'غ':1000, + }, + english: (() => { const m = {}; const A = 'A'.charCodeAt(0); for (let i = 0; i < 26; i++) m[String.fromCharCode(A + i)] = i + 1; return m; })(), +}; + +function gematria(input, lang = 'all') { + const steps = [`Input: ${input}`, `Language: ${lang}`]; + const langs = lang === 'all' ? Object.keys(GEMATRIA_MAPS) : [lang]; + const results = {}; + for (const L of langs) { + const map = GEMATRIA_MAPS[L]; + let total = 0; + const breakdown = []; + for (const ch of [...input]) { + const uc = ch.toUpperCase(); + const v = map[ch] ?? map[uc] ?? 0; + if (v) { breakdown.push(`${ch}=${v}`); total += v; } + } + results[L] = total; + steps.push(` ${L.toUpperCase()}: ${total}`); + if (breakdown.length) steps.push(` ${breakdown.join(' + ')}`); + else steps.push(` none`); + } + const summary = Object.entries(results).map(([k, v]) => `${k}:${v}`).join(' '); + return { result: summary, steps, totals: results }; +} + +// ── Transform dispatcher ───────────────────────────────────────── +function splitDecimal(s) { + const i = s.indexOf('.'); + if (i === -1) return [s, null]; + return [s.slice(0, i), s.slice(i+1)]; +} + +function joinDecimal(left, right) { + return right !== null ? left + '.' + right : left; +} + +function preprocess(input) { + // Always apply zero + decimal rules before the mode transform + const [left, right] = splitDecimal(input); + const zL = processZeros(left); + const zR = right !== null ? processZeros(right) : null; + return joinDecimal(zL, zR); +} + +function transform(input, mode, align, lang = 'all') { + input = preprocess(input); + switch (mode) { + case 1: return scenario1(input); + case 2: { const r = zitsbitTransform(input); return { result: r, steps: [`Input: ${input}`, `Zitsbit: ${r}`] }; } + case 3: return scenario3(input); + case 5: { const r = blockCycle(input, 3, align); return r; } + case 6: return scenario6(input); + case 7: return scenario7(input); + case 8: return scenario8(input); + case 9: return scenario9(input); + case 10: return gematria(input, lang); + default: return scenario1(input); + } +} + +// ── CLI ────────────────────────────────────────────────────────── +const VERSION = '1.3.0'; +const args = process.argv.slice(2); + +if (args.includes('--version') || args.includes('-v')) { + console.log(`zitsbit v${VERSION}`); process.exit(0); +} + +if (args.length === 0 || args.includes('--help') || args.includes('-h')) { + console.log(`Usage: zitsbit [-m ] [-a ] [--glyph] [--perspective ] + +Flags: + -m, --mode Scenario mode (default: 1) + -a, --align Align block cycle to start with this character (mode 5) + -g, --glyph Convert digits to symbolic glyphs + -p, --perspective Orbit rotation angle (0|90|180|270) + -l, --lang Gematria language: hebrew|arabic|english|all (mode 10) + -v, --version Show version + -h, --help Show help + +Modes: + 1 Reverse Cycle (rev → zitsbit, iterative with fallback) (default) + 2 Direct Rule (zitsbit only, no reverse) + 3 Solar Cycle (digit phase mapping) + 5 Block Cycle (rotate-left 3 → static map → cycle detect) + 6 Retrograde only (each digit -1) + 7 Normal Mirror (reverse + static glyph map) + 9 Mirror then Reverse (static glyph → reverse) + 10 Gematria (letter → numeric value, hebrew/arabic/english) + +Zero & decimal rules applied automatically.`); + process.exit(0); +} + +let mode = 1, perspective = 0, glyph = false, align = '', lang = 'all', value; + +const modeIdx = args.indexOf('--mode'); +const modeShort = args.indexOf('-m'); +const modeFinal = modeIdx !== -1 ? modeIdx : modeShort; +if (modeFinal !== -1 && modeFinal+1 < args.length) { + mode = parseInt(args[modeFinal+1], 10); args.splice(modeFinal, 2); +} +const glyphIdx = args.indexOf('--glyph'); +if (glyphIdx !== -1) { glyph = true; args.splice(glyphIdx, 1); } +const gIdx = args.indexOf('-g'); +if (gIdx !== -1) { glyph = true; args.splice(gIdx, 1); } +const alignIdx = args.indexOf('--align'); +if (alignIdx !== -1 && alignIdx+1 < args.length) { align = args[alignIdx+1]; args.splice(alignIdx, 2); } +const aIdx = args.indexOf('-a'); +if (aIdx !== -1 && aIdx+1 < args.length) { align = args[aIdx+1]; args.splice(aIdx, 2); } +const langIdx = args.indexOf('--lang'); +const lIdx = args.indexOf('-l'); +const li = langIdx !== -1 ? langIdx : lIdx; +if (li !== -1 && li+1 < args.length) { lang = args[li+1]; args.splice(li, 2); } +const perspIdx = args.indexOf('--perspective'); +const pIdx = args.indexOf('-p'); +const pi = perspIdx !== -1 ? perspIdx : pIdx; +if (pi !== -1 && pi+1 < args.length) { + perspective = parseInt(args[pi+1], 10); args.splice(pi, 2); +} + +value = args.join(' '); +if (!value) { console.error('Error: no value provided.'); process.exit(1); } + +// Perspective pre-processes, then mode runs on the rotated result +const orb = orbitTransform(value, perspective); +const input = orb !== null ? orb : value; +let output = transform(input, mode, align, lang); +let result = output.result; +if (glyph) result = applyGlyphs(result); +console.log(`\nResult: ${result}\n`); +console.log(output.steps.join('\n'));