Easy-to-manage touch screens
무료 오픈소스 터치스크린으로 USB 설정 가이드, 드래그‑드롭 편집기, 로컬 제어를 제공하며 Home Assistant용으로 제작되었습니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Canonical for: what AXIS is, methodology, calculation accuracy, design tokens, setup and deployment basics. Lives elsewhere: architecture, core libs, the reading pipeline (models, quality gate, cost) and tests →
CLAUDE.md; product law →DOCTRINE.md. If this file andCLAUDE.mddisagree about code,CLAUDE.mdand the code win. Fix this file, don't follow it.
Tropical maps the psychological architecture of a self. Sidereal maps the incarnational conditions it navigates. The divergence is where this chart actually lives — AXIS holds both open.
Live: axis-astro.vercel.app
AXIS generates natal chart readings using both the Western Tropical and Vedic Sidereal zodiac systems simultaneously — and never merges them. The two systems disagree by the ayanamsa (~23.85°), and that disagreement is the product: AXIS computes both charts in full and holds open the distance between them. Divergence is not noise to be averaged out; it is the most informative part of the chart.
Most astrology apps pick one system. AXIS treats them as two maps of different layers of a person that do not resolve into one picture:
AXIS is written for readers who take astrology seriously — students of the technical literature, therapy-adjacent practitioners, those formed by the contemplative traditions. The interpretive vocabulary assumes a working understanding of both the Tropical and Sidereal frameworks before arriving. The chart is read once at depth rather than re-explained across a daily push notification.
Readings are written in continuous analytical prose. No bullet points. No generic affirmations. No predictions. Every sentence earns its place.
| Parameter | Choice | Rationale |
|---|---|---|
| House system | Whole Sign | Consistent for both Tropical and Sidereal; used throughout code, wheel, and interpretation engine |
| Ayanamsa | Lahiri | IAU standard for Jyotish; ~23.85° at J2000, precessing at 50.2564"/yr |
| Lunar nodes | True (osculating) node | Meeus Ch. 22 mean node + 4-term periodic corrections; matches Swiss Ephemeris to <0.05°. Oscillates ±1.5° around the mean with a ~173-day period. |
| Dasha system | Vimshottari | Used for current-chapter contextualisation, not event prediction |
| Midheaven | Shown as separate angle | MC is NOT the Whole Sign 10th-house cusp — displayed independently on the wheel |
Birth time sensitivity: Ascendant, house placements, MC, Moon degree, and dasha timing all depend on an accurate birth time. AXIS flags readings with an unknown birth time and discloses which elements are unreliable.
AXIS uses two complementary ephemeris sources:
1. Local VSOP87 / ELP2000 engine (astronomia package) — Sun, Moon, Mercury through Neptune, Rahu/Ketu. Full VSOP87 planetary theory and ELP2000 lunar theory. These are the same algorithms used in professional desktop astrology software.
2. JPL Horizons REST API — Pluto position. JPL Horizons (operated by NASA/JPL) returns positions computed from the JPL DE440 planetary ephemeris (Park et al. 2021), the current standard for solar system dynamics. DE440 accuracy for Pluto: < 1 arcsecond. AXIS fetches the Pluto position at chart calculation time via a single HTTP call to the Horizons API, with automatic fallback to the local Meeus polynomial if the API is unavailable.
| Body | Method | Accuracy (1800–2050) |
|---|---|---|
| Sun | VSOP87 via solar.apparentVSOP87 (nutation + aberration included) | < 1 arcsecond |
| Moon | ELP2000 + nutation correction | < 10 arcseconds |
| Mercury–Neptune | VSOP87 heliocentric + geocentric conversion + light-time + nutation | < 1 arcminute |
| Pluto | JPL Horizons DE440 (fallback: Meeus Ch. 37, ~15–60 arcmin) | < 1 arcsecond |
| Rahu/Ketu | True node: Meeus Ch. 22 + periodic corrections | < 0.05° vs. Swiss Ephemeris osculating node |
| Lahiri ayanamsa | Linear precession formula | Within ~0.01° of the IAU reference value |
Every generated chart displays the active Pluto ephemeris source ("JPL Horizons DE440" or "⚠ local fallback") in the reading header so users know which source was used.
AXIS requests apparent geocentric ecliptic longitude of date (Horizons OBSERVER quantity 31, CENTER=geocenter, APPARENT=AIRLESS). This is the same coordinate frame VSOP87 + nutation produces for all other planets — mean ecliptic and equinox of the tabulation date, light-time corrected, aberration included, no atmospheric refraction. The values are directly comparable and substitutable.
Horizons currently uses DE440 for dates in the 1550–2650 range. DE440 is the successor to DE431, published by Park et al. (2021). It is not Swiss Ephemeris (which wraps DE431/DE441 in a C library), but it uses the same underlying JPL integration and is at the same accuracy level.
swisseph (the npm wrapper for Swiss Ephemeris) requires a native C binary compiled for the target platform. Vercel Lambda runs in a read-only environment where pre-compiled C binaries cannot be shipped as part of a Next.js bundle. Additionally, JPL ephemeris data files are 30–180MB, exceeding Vercel's 50MB compressed bundle limit. These are hard architectural constraints, not tradeoffs.
The JPL Horizons API is the practical equivalent — same JPL data, same accuracy — accessed via HTTP instead of a native binary. For the 10 planets calculated via VSOP87/ELP2000, the current engine is already at Swiss Ephemeris accuracy. Horizons brings Pluto up to the same standard.
Ephemeris benchmark: node scripts/benchmark-pluto.mjs compares Meeus Ch.37 vs Horizons DE440 across representative dates (1930–2025) and reports the difference in arcminutes per date. See BENCHMARK.md for the full methodology and pre-computed Meeus values.
| Layer | Technology |
|---|---|
| Framework | Next.js 16.x (App Router) |
| Language | TypeScript |
| AI backend | Anthropic Claude Sonnet 5 for generation and Opus 5 for evaluation, via streaming API with prompt caching |
| Planetary calculations | VSOP87 (astronomia) + ELP2000 Moon + JPL Horizons DE440 Pluto |
| Geocoding | OpenStreetMap Nominatim |
| Timezone | tz-lookup (offline IANA lookup) |
| Deployment | Vercel |
| Fonts | Cormorant Garamond · Cinzel · Courier Prime |
AXIS uses a restrained dark-void palette. Copper is the primary accent, ratified July 2026 (the copper→gold migration is cancelled; there is no gold token). Cyan signals active computation, selected states, streaming, and focus. Violet marks unresolved tension, dissonance, and liminal states.
| Token | Value | Role |
|---|---|---|
--void | #02030A | True background black-blue |
--bg | #030212 | Page base |
--surface | #0C0B0E | Panels and form surfaces (neutral lifted base) |
--surface-2 | #131114 | Raised cards |
--reading-surface | #0C0B0E | Raised neutral surface behind long-form reading prose only (see DOCTRINE.md) |
--text | #EAE8F8 | Primary star-white text |
--text-2 | #A8A4C8 | Body support text |
--text-3 | #9490C4 | Labels and metadata |
--copper | #B87333 | Base identity accent — wordmark, primary CTAs, offset wedge, section rituals, symbolic emphasis |
--copper-bright | #D89455 | Fine linework, hairlines, chart ticks, small mono labels on void |
--copper-light | #F0B978 | Finest / dimmest-context lines; rare highlight or glow edge |
--copper-dim | #5A2F18 | Borders, shadows, subdued rules |
--copper-glow | rgba(184, 115, 51, 0.18) | Soft ambient accent |
--cyan | #2CC8C0 | Active computation and focus state |
--violet | #7844FF | Dissonance, contradiction, liminal insight |
Two-tier linework rule: base copper #B87333 is too dim for 1px lines and tiny type on the void. ALL fine linework, hairlines, chart ticks, and small mono labels use --copper-bright (or --copper-light for the finest/dimmest contexts). Only identity elements — wordmark, primary CTA fill, the offset wedge, section ritual rules — stay base --copper. No gradient blends two accent colours. All tokens are defined in src/app/globals.css.
Per-file architecture, every core lib and component, the reading pipeline and the test suite are documented in CLAUDE.md. They are not repeated here, because a second copy drifts. The top-level layout:
src/
├── app/ — pages: / (main app), /method, /guides, /sample, /synastry; globals.css holds the design tokens
│ └── api/ — calculate · synastry · geocode · timezone · reading (streaming Claude endpoint)
├── components/ — the dossier (DossierHeader, FrameControl, FrameShiftWheel, ReadoutRail, ReadingPanel), BirthForm, synastry panels, site chrome, landing/
└── lib/ — calculation engine, interpretation engine, prompts, quality gate, cache, reading thread
scripts/ — benchmark, eval harness, state checks
Both Tropical and Sidereal charts use Whole Sign houses throughout — for planet assignments, the chart wheel, and the interpretation engine. The MC (Midheaven) is computed separately as the ecliptic projection of the meridian and is displayed as an independent angle, not as the 10th-house cusp.
lib/interpretation-engine.ts sits between raw chart data and the Claude prompt. For each section it derives first-principles facts — essential dignity, sign modification, house environment, dispositor chain, aspects with applying/separating status, and a weighted evidence block for psychological axes (attachment/detachment, emotional suppression, etc.) — and formats them as a structured context block injected into every reading request.
The evidence-weighted approach (rather than categorical rules) means Claude receives the chart evidence, not pre-formed verdicts. For example, the Moon cross-reference for Sun and Mars sections lists specific attachment and detachment indicators with their weights, then states the evidence balance — so the interpretation can name the genuine tension rather than defaulting to a sign-element cliché.
Four reading types, each composed of sequential per-planet streaming requests to the Claude API. Per-section retry (2 attempts) prevents a single failed request from blocking the rest of the reading. Failed sections produce a visible placeholder so the readable portions remain intact.
Every generated section then goes through the LLM quality gate (lib/reading-quality-gate.ts), which is live. It runs as evaluate-and-recache after the section has finished streaming (gateForCache(), registered with Next's after()), so it adds no latency for the reader. It decides only what gets cached: the first reader of an uncached section sees the first pass, and every later reader gets the gated (and, where needed, repaired) text. The mechanics, thresholds and guards are in CLAUDE.md under /api/reading and lib/reading-quality-gate.ts.
synthesis, kept for cache-key stability) — Where the Chart Is Least Negotiable, Where They Part, The Central Tension, Living the Divergence. Its context block is a single deterministic SHARED DIVERGENCE PLAN (buildDivergencePlan) used unchanged by all four sections: every body in both frames with degree, dignity, retrogradation, sidereal nakshatra and sign-ruler condition; concordances in two grades (full, and same-sign with a house shift); divergences ranked by interpretive weight of the body and structural size of the shift; the aspects that link them; dasha timing and sidereal yogas; and explicit reliability limits when birth time is unknown. The reading names where the systems agree and where they pull apart, names the divergences it did not walk as still unresolved, and never averages the two charts into one answer.synastry-calc.ts computes inter-aspects (orb-limited, 5 major aspects) and a midpoint composite chart from both natal charts. For the composite-focused sections (composite_chart, central_dynamic), an elite chart block for the composite — dignity labels, chart ruler, and direction — is appended to the prompt context alongside the position table. The /api/synastry route handles calculation; SynastryReadingPanel streams the interpretation.| Variable | Description |
|---|---|
ANTHROPIC_API_KEY | Required. Set in Vercel dashboard → Environment Variables. |
UPSTASH_REDIS_REST_URL | Recommended. Upstash Redis REST endpoint for the reading cache. Create a free database at console.upstash.com. Falls back to no-op (no caching) when absent. |
UPSTASH_REDIS_REST_TOKEN | Recommended. Upstash Redis REST token (paired with the URL above). |
Operational switches for the reading pipeline (AXIS_READINGS_ENABLED, AXIS_GATE_ENABLED, AXIS_READING_RATE_LIMIT_MAX, …) are described in CLAUDE.md.
git clone https://github.com/kayrmac23-droid/Axis-astro.git
cd Axis-astro
npm install
Create a .env.local file:
ANTHROPIC_API_KEY=your_key_here
npm run dev # development server at http://localhost:5000
npm test # run test suite (vitest)
npm run lint # ESLint
npm run build # production build
App runs at http://localhost:5000.
Deployed via Vercel connected to this GitHub repo. Every push to main triggers an automatic production deployment.
Each API route sets its maxDuration via export const in the route file itself (the canonical Next.js App Router pattern; vercel.json only declares the framework). The route files hold the current values, and CLAUDE.md lists them.
This section describes what is hardened now and what requires distributed infrastructure for true production scale.
Hardened (current state):
next.config.js headers(): a scoped Content-Security-Policy (default-src 'self', frame-ancestors 'none', object-src 'none', base-uri 'self', allow-listed to the app's real external surface — PostHog and Vercel Insights), plus X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy (camera/microphone/geolocation denied), and Strict-Transport-Security (2-year HSTS with includeSubDomains; preload)/api/reading validates section and planetSection against explicit allow-lists before processing/api/reading recomputes chart positions server-side from validated birth data rather than trusting client-supplied positions, preventing cache poisoning via forged planet data/api/reading enforces a 16 KB payload size limit/api/reading applies a Redis-backed per-IP rate limiter (20 req / 60s fixed window via Upstash, with an atomic Lua INCR+EXPIRE; in-memory fallback when Redis env vars are absent)/api/calculate and /api/synastry enforce a 16 KB payload size limit with explicit JSON parse guard (reject oversized or malformed bodies before any processing)/api/calculate applies a Redis-backed per-IP rate limiter (30 req / 60s); /api/synastry applies 20 req / 60s/api/geocode enforces a 200-character query length limit and a Redis-backed per-IP rate limiter (30 req / 60s); results are field-whitelisted rather than forwarding raw Nominatim output/api/timezone applies a Redis-backed per-IP rate limiter (60 req / 60s) so the offline lookup cannot be used as an unbounded compute or scraping surfacestop_reason: max_tokens) are not cached and surface an inline notice to the user@upstash/redis). Persists across cold starts and is shared between concurrent serverless instances. 30-day TTL. Requires UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN env vars; falls back to no-op when absent.Distributed — no warm-instance bypass:
External service dependencies:
CLAUDE.md (/api/reading). Measured cost per reading comes from the [AXIS_USAGE] log lines or npm run eval. API key must be set in Vercel environment variables.ssd.jpl.nasa.gov) — one HTTP call per chart calculation for the Pluto position. Falls back to the local Meeus Ch. 37 polynomial (~15–60 arcmin vs DE440 across 1930–2025; see BENCHMARK.md) if unreachable.astronomia/pluto; ~15–60 arcminutes vs DE440) and the chart header displays "⚠ local fallback." The fallback is noted so users know the accuracy tier their chart used. See BENCHMARK.md.ssd.jpl.nasa.gov per chart calculation for the Pluto position. If the endpoint is unreachable (downtime, network policy), the fallback engine activates transparently.