{"id":42071844,"url":"https://github.com/capachow/arcane","last_synced_at":"2026-01-26T09:02:45.948Z","repository":{"id":240736492,"uuid":"85868939","full_name":"capachow/arcane","owner":"capachow","description":"A deceptively powerful 12kb dependency-free single-file PHP microframework built to keep things easy and minimal.","archived":false,"fork":false,"pushed_at":"2026-01-24T08:01:08.000Z","size":112,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-24T11:33:17.626Z","etag":null,"topics":["arcane","micro-framework","microframework","php","php-framework","php-micro-framework","web-development","zero-dependency"],"latest_commit_sha":null,"homepage":"https://chat.arcane.dev","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/capachow.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["capachow"]}},"created_at":"2017-03-22T19:40:34.000Z","updated_at":"2026-01-24T00:07:43.000Z","dependencies_parsed_at":"2024-05-20T18:58:20.296Z","dependency_job_id":null,"html_url":"https://github.com/capachow/arcane","commit_stats":null,"previous_names":["media76/arcane","capachow/arcane"],"tags_count":26,"template":false,"template_full_name":null,"purl":"pkg:github/capachow/arcane","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capachow%2Farcane","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capachow%2Farcane/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capachow%2Farcane/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capachow%2Farcane/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/capachow","download_url":"https://codeload.github.com/capachow/arcane/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capachow%2Farcane/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28771510,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T08:38:24.014Z","status":"ssl_error","status_checked_at":"2026-01-26T08:38:22.080Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arcane","micro-framework","microframework","php","php-framework","php-micro-framework","web-development","zero-dependency"],"created_at":"2026-01-26T09:00:38.515Z","updated_at":"2026-01-26T09:02:45.942Z","avatar_url":"https://github.com/capachow.png","language":"PHP","readme":"## Arcane Microframework\n\n\u003e *Arcane is unconventional but beautifully intuitive. It is intentionally different, breaking away from modern frameworks to encourage critical thinking without the dependence and overhead of complex systems. It brings out the fun in building for the web by automating the features you want, while making it easier to apply the ones you need.*\n\nAt its core, Arcane is a tiny `12kb` single-file PHP microframework designed to keep things easy and minimal. It uses a filesystem-first workflow where files map directly to routes, and context-aware helpers and assets load automatically. Perfect for anyone who wants a fast, flexible tool with zero setup.\n\n  - Clean configuration free URLs\n  - Unique filesystem defined routing\n  - Helpers autoloaded by context\n  - Layouts wrap pages automatically\n  - Robust localization kept simple\n  - Architecture driven by directories\n  - Simple ENV file configuration\n  - HTML minification for performance\n  - Native PHP minimal learning curve\n  - Zero external dependencies needed\n\n`Less config. More craft.`\n\n## Installation\n\n**[https://arcane.dev/download](https://arcane.dev/download)** or copy via terminal:\n\n``` shell\ncurl -fsLO copy.arcane.dev/index.php\n```\n\n\u003e \u003ccode\u003e\u003cdel\u003ecomposer create-project capachow/arcane\u003c/del\u003e\u003c/code\u003e It's a single file with zero dependencies. You should just curl it.\n\nSimply drop `index.php` into your project and open it in your browser. Arcane conjures the rest like magic.\n\n## Documentation\n\n1. [Philosophy \u0026 Architecture](#1-philosophy--architecture)\n2. [The Four Functions](#2-the-four-functions)\n3. [Routing \u0026 Pages](#3-routing--pages)\n4. [Layouts, Rendering, and Includes](#4-layouts-rendering-and-includes)\n5. [Helpers \u0026 Autoload Cascade](#5-helpers--autoload-cascade)\n6. [Automatic CSS/JS Assets](#6-automatic-cssjs-assets)\n7. [Localization and Translation](#7-localization-and-translation)\n8. [Environment \u0026 Settings](#8-environment--settings)\n9. [Page Directives](#9-page-directives)\n10. [Runtime Constants](#10-runtime-constants)\n11. [Troubleshooting \u0026 Notes](#11-troubleshooting--notes)\n12. [Requirements and Ecosystem](#12-requirements-and-ecosystem)\n\n---\n\n### 1. Philosophy \u0026 Architecture\n\nArcane operates on a single governing principle: **location is logic**.\n\nModern web development often drifts into configuration chaos. Many frameworks are built to satisfy enterprise edge cases, and everyone else ends up carrying that weight. Arcane takes the opposite stance. It focuses on the work that ships real projects, like routing, templating, and helpers, and treats \"less\" as a **deliberate discipline**, not a missing feature. By focusing on what most projects actually need, Arcane makes a promise rooted in honesty, freedom, and focus. You should not have to carry the baggage for features you will never use.\n\nThat discipline comes from *unified primitives* and a filesystem-first approach. There is no route registry or hidden sigils to maintain. If you want a page, you create a file. By keeping assets, logic, and views close together, Arcane encourages *cognitive locality*. You build where it makes sense instead of hunting through scattered configuration.\n\nDependencies also break. They age, conflict, and require maintenance. Arcane stays **dependency-free** at its core, keeping your project stable and grounded in standard PHP, so you are not betting your site on whether a framework stays maintained.\n\n**The Request Lifecycle**:\n\nInstead of a complex event loop, Arcane follows a linear path of discovery:\n\n1. **Match:** The URL is mapped directly to the closest physical file in `/pages`, normalizing paths for SEO.\n2. **Collect:** Arcane walks the directory tree down to that file, channels only relevant helpers, data, and assets.\n3. **Build:** The page executes within this prepared environment, generating the `CONTENT` constant.\n4. **Return:** Output is wrapped in the layout, assets are injected, and the final response is sent to the browser.\n\n---\n\n### 2. The Four Functions\n\nArcane keeps things minimal. You can build simple to complex applications using just these four globals. These global functions are available everywhere.\n\n2.1 **`env(string, string)`**: Retrieves environment variables or feature flags.\n\n- *Note*: Automatically converts strings `true`, `false`, or `null` into actual booleans or nulls.\n\n``` php\n\u003c?php $mode = env('IS_ALLOWED', 'true'); ?\u003e\n\n\u003c?php if(env('IS_ALLOWED')) { ... } ?\u003e\n```\n\n2.2 **`path(mixed, boolean)`**: The unified tool for inspecting where you are and generating where you want to go.\n\n  -  A. **Current Request** [empty]:\n\n``` php\n\u003c?= path(); # /blog/2024/ ?\u003e\n```\n\n  - B. **Get Segment** [integer]:\n\n``` php\n\u003c?= path(1); # first-segment ?\u003e\n\u003c?= path(3); # third-segment (null if missing) ?\u003e\n```\n\n  - C. **Generate URL** [string|array]:\n\n    - *Note*: If a locale is active (example: `en+us`), Arcane automatically prefixes the generated URL (`/us/about/`). You do not have to manually manage language prefixes.\n    - *Normalization*: If you provide a path without an extension or parameters (no `.` or `?`), Arcane assumes it is a page route and adds a trailing slash to normalize SEO.\n\n``` php\n\u003c?= path('/about'); # normalized to /about/ ?\u003e\n\u003c?= path('/shop/cart/'); # /us/shop/cart/ (if active locale) ?\u003e\n\u003c?= path(['IMAGES', 'logo.svg']); # /images/logo.svg (no matter the URL) ?\u003e\n```\n\n  - D. **System Path** [string|array][boolean]:\n\n    - Pass `true` as the second argument to get the absolute server path for `include()` or `require()`.\n\n``` php\n\u003c?= path('/folder/custom.php', true); ?\u003e\n\u003c?= path(['HELPERS', 'custom.php'], true); ?\u003e\n```\n\n2.3 **`relay(string, mixed)`**: This is how you \"yield\" data from a page to the layout.\n\n  - **Usage**: Pages pass data with `relay('TITLE', 'My Page')`. Layouts then echo `TITLE`.\n  - **Advanced**: If you pass a function (callable), Arcane captures the output and relays the resulting HTML.\n\n``` php\n\u003c?php relay('TITLE', 'Home'); ?\u003e\n\u003c?php relay('SIDEBAR', function() { ?\u003e\n  \u003ch2\u003eSidebar\u003c/h2\u003e\n  \u003cp\u003eInjected into the layout.\u003c/p\u003e\n\u003c?php }); ?\u003e\n```\n\n2.4 **`scribe(string|array, array)`**:\n\nReturns a translated string based on the active locale. If no translation exists, it returns the fallback text provided. Localization is optional.\n\n``` php\n\u003c?= scribe('Welcome'); ?\u003e\n\u003c?= scribe('Hello :name', [':name' =\u003e 'John']); # Hello John ?\u003e\n\u003c?= scribe(['missing.key', 'Fallback']); ?\u003e\n```\n\n---\n\n### 3. Routing \u0026 Pages\n\nIn Arcane, a file *is* a URL. This eliminates the need for a `routes.php` file.\n\n  - `pages/about.php` → `/about/`\n  - `pages/blog/index.php` → `/blog/`\n  - `pages/shop/checkout.php` → `/shop/checkout/`\n\nWhat if you need dynamic segments, like `/blog/my-post/`? Arcane resolves the *closest* physical file first.\nIf you visit `/blog/my-post/`, Arcane loads `pages/blog.php` (if it exists) and passes `my-post` as a parameter.\n\nYou control valid dynamic segments using `define('ROUTES', array)` inside the page file.\n\n*Example*: `pages/blog.php`\n\n```php\n\u003c?php define('ROUTES', [\n  ['history'], # /blog/history/\n  [['2023', '2024']], # /blog/2023/ or /blog/2024/\n  ['*'] # /blog/anything/\n]);\n\n$slug = path(1); ?\u003e\n```\n\n  - String values are an exact match.\n  - Array values are an allow-list of options.\n  - Wildcard matching with `*`. If the URL fails this validation, Arcane redirects to the closest valid path.\n\n---\n\n### 4. Layouts, Rendering, and Includes\n\nArcane separates logic from presentation using a simple wrapper system.\n\n  1. **The Page**: Executes first. It defines data, handles logic, and outputs HTML. This output is captured in the constant `CONTENT`.\n  2. **The Layout**: Executes second. It outputs the HTML structure (`\u003chtml\u003e`, `\u003cbody\u003e`) and echoes `CONTENT` where the page should appear.\n\nThe layout also has access to `STYLES` and `SCRIPTS` (auto-generated tags) and any constants you defined in the page using `relay()`.\n\n*Example*: `layouts/default.php`\n\n``` php\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003e\u003c?= defined('TITLE') ? TITLE : 'Arcane'; ?\u003e\u003c/title\u003e\\\n    \u003c?= STYLES; ?\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n      \u003c?= CONTENT; ?\u003e\n      \u003c?php if(defined('SIDEBAR')) { ?\u003e\n        \u003caside\u003e\n          \u003c?= SIDEBAR; ?\u003e\n        \u003c/aside\u003e\n      \u003c?php } ?\u003e\n      \u003c?= SCRIPTS; ?\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n---\n\n### 5. Helpers \u0026 Autoload Cascade\n\nThis is one of Arcane's most \"refreshing\" features. Instead of autoloading every class in the universe, Arcane loads helpers based on context. Helpers are PHP files that return a value (`mixed`). They become variables in your page matching their filename.\n\n*Example*: `helpers/cart.php`\n\n``` php\n\u003c?php return [\n  'items' =\u003e 3,\n  'total' =\u003e 99.00\n]; ?\u003e\n```\n\n*Example*: `pages/checkout.php`\n\n``` php\n\u003cp\u003eItems: \u003c?= $cart['items']; ?\u003e\u003c/p\u003e\n\u003cp\u003eTotal: $\u003c?= number_format($cart['total'], 2); ?\u003e\u003c/p\u003e\n```\n\n**Context-aware Cascade**:\n\nIf you are visiting `/shop/checkout/`, Arcane looks for helpers in this specific order, merging them as it goes:\n\n  1. `helpers/*.php` (global scoped helpers)\n  2. `helpers/shop/*.php` (section scoped helpers)\n  3. `helpers/shop/checkout/*.php` (page scoped helpers)\n\nThis is done because you can have a helper named `cart.php`:\n\n  - In `helpers/cart.php`, it might define a generic cart.\n  - In `helpers/shop/cart.php`, you can override it with a detailed shopping cart specific to the shop section.\n  - The most specific helper always wins.\n\n*Note*: Helpers are imbued into Pages. If a helper needs another helper, you must `include` it explicitly.\n\n``` php\n\u003c?php $truncate = include(path(['HELPERS', 'truncate.php'], true));\n\nreturn [\n  'excerpt' =\u003e $truncate($post['body'], 160)\n]; ?\u003e\n```\n\n---\n\n### 6. Automatic CSS/JS Assets\n\nForget complicated configurations for simple tasks. Arcane uses *convention over wiring*.\n\nWhen a layout is active, Arcane scans your `/styles` and `/scripts` directories. If a file matches the current layout or the current page path, it is automatically bound in the `STYLES` or `SCRIPTS` constants.\n\n**Context-aware Cascade**:\n\nFor a user visiting `/blog/post` using the `default` layout, Arcane looks for and auto-injects:\n\n  1. **Layout Assets**: `styles/default.css` \u0026 `styles/default.js`\n  2. **Section Assets**: `styles/pages/blog.css` \u0026 `styles/pages/blog.js`\n  3. **Page Assets**: `styles/pages/blog/post.css` \u0026 `styles/pages/blog/post.js`\n\n*The Benefit*: You can create `styles/pages/blog.css` and it will automatically apply to every blog post, but nowhere else on the site. No manual `\u003clink /\u003e` or `\u003cscript\u003e` tags required. All assets are cache-busted automatically via `?m=` timestamp.\n\n---\n\n### 7. Localization and Translation\n\nArcane handles localization via folder naming conventions, supporting both language switching and country specific content.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eLanguage Locale\u003c/th\u003e\n    \u003cth\u003eCountry Locale\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003cpre lang=\"txt\"\u003elocales/\n├─ en/\n│  ├─ en-ca.json\n│  ├─ en+us.json\n│  └─ en.json\n├─ es/\n│  ├─ es+mx.json\n│  ├─ es-us.json\n│  └─ es.json\n├─ fr/\n│  └─ fr+ca.json\n├─ ca.json\n└─ us.json\u003c/pre\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cpre lang=\"txt\"\u003elocales/\n├─ ca/\n│  ├─ en-ca.json\n│  └─ fr-ca.json\n├─ mx/\n│  └─ es-mx.json\n├─ us/\n│  ├─ en-us.json\n│  ├─ es-us.json\n│  ├─ fr-us.json\n│  └─ us.json\n├─ es.json\n└─ en.json\u003c/pre\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n**Folder Naming (`-` vs `+`)**:\n\n  - `locales/en/en-us.json` creates a **two-segment URL** (`/en/us/`).\n  - `locales/en/en+us.json` creates a **one-segment URL** (`/en/`). Country is active, but hidden from the URL.\n\nArcane weaves translations intelligently. For `en-us`, it loads:\n\n  1. `locales/us.json` (country defaults)\n  2. `locales/en/en.json` (language defaults)\n  3. `locales/es/en-us.json` (specific overrides)\n\nLater files override earlier ones, allowing you to define a base language and only tweak specific keys for countries.\n\n*Note*: If you set `SET_LOCALE`, Arcane will detect the browser's `Accept-Language` header and redirect the user to the best matching locale path automatically.\n\n---\n\n### 8. Environment \u0026 Settings\n\nConfiguration is handled via `.env`. If `.env` is missing, Arcane defaults to `.env.example`.\n\n8.1 **Key Settings (`SET_`)**:\n\n| Setting | Default | Purpose |\n| :--- | :--- | :--- |\n| `SET_ERRORS` | `false` | Set to `true` to debug PHP errors. |\n| `SET_INDEX` | `'index'` | Change the default directory file (example: `home.php`). |\n| `SET_LAYOUT` | `null` | Define a global layout wrapper for all pages. |\n| `SET_LOCALE` | `null` | Set a default `BCP 47` tag to enable auto-localization. |\n| `SET_MINIFY` | `true` | Toggles HTML minification to keep output small. |\n\n8.2 **Directories (`DIR_`)**:\n\nYou can remap any default folder (like `pages` to `views`) by setting `DIR_PAGES` in your environment.\n\n``` env\nDIR_PAGES=/pages/\nDIR_LAYOUTS=/layouts/\nDIR_HELPERS=/helpers/\nDIR_SCRIPTS=/scripts/\nDIR_STYLES=/styles/\nDIR_LOCALES=/locales/\nDIR_IMAGES=/images/\n```\n\n---\n\n### 9. Page Directives\n\nDirectives are constants defined at the top of a *page* file. They act as the \"controller\" logic for that specific page.\n\n  - `define('LAYOUT', 'filename')`: Overrides the global layout for this specific page.\n  - `define('REDIRECT', '/path/')`: Immediately redirects the user. Relative paths are auto-resolved; absolute URLs are respected.\n  - `define('ROUTES', array)`: Defines acceptable \"extra\" URL segments for this page (see [Routing \u0026 Pages](#3-routing--pages)).\n\n---\n\n### 10. Runtime Constants\n\nArcane provides global constants to give you instant access to the application state.\n\n10.1 **Content \u0026 Output**:\n\n  - `CONTENT`: The rendered HTML of the page.\n  - `HELPERS`: The merged and injected helpers for pages and layouts.\n  - `STYLES`: The injected `\u003clink\u003e` tags (layout must be active).\n  - `SCRIPTS`: The injected `\u003cscript\u003e` tags (layout must be active).\n\n10.2 **Routing \u0026 Location**:\n\n  - `URI`: The URL segments array (locale segments removed when applicable).\n  - `PATH`: The resolved “base path” for the matched page.\n  - `PATHS`: Hierarchical path list used for helper/asset discovery.\n  - `PAGEFILE`: Absolute path to the resolved PHP page file.\n  - `LAYOUTFILE`: Absolute path to the resolved PHP layout file (when used).\n\n10.3 **Localization**:\n\n  - `LOCALES`: Discovered locales grouped by folder.\n  - `LOCALE`: Array containing `CODE`, `COUNTRY`, `FILES`, `LANGUAGE`, and `URI` (when active).\n  - `TRANSCRIPT`: The merged translations for the active locale (when active).\n\n10.4 **App Configuration**:\n\n  - `APP`: Derived runtime info containing `DIR`, `ROOT`, `START`, `QUERY`, and `URI`.\n  - `DIR`: Directory map (from defaults + any DIR_* overrides).\n  - `SET`: Settings map (from defaults + any SET_* overrides).\n\n---\n\n### 11. Troubleshooting \u0026 Notes\n\n  - **Trailing Slashes**: Arcane normalizes \"page-like\" routes to have trailing slashes. This prevents duplicate content issues for SEO.\n  - **Minification**: By default, `SET_MINIFY` is `true`. It strips whitespace and comments. If your HTML looks broken, try setting this to `false` in `.env` to debug.\n  - **Helper Collisions**: If you have helpers with the same name in different folders, remember: *Scope wins*. The helper closest to the current page path overrides the global one.\n  - **Errors**: To see full PHP error details during development, ensure `SET_ERRORS` is set to `true` in your environment.\n\n---\n\n### 12. Requirements and Ecosystem\n\nArcane is minimal by design. It doesn't include heavy tomes, but it offers a system to plug them in easily.\n\n  - Arcane **requires** PHP \u003e= 8.2 and Apache with the `AllowOverride All` directive enabled.\n  - [Arcane Helpers](https://github.com/MEDIA76/arcane-helpers) is a collection of drop-in files for common tasks (Markdown parsing, OAuth, database access).\n  - [Creating an issue](https://github.com/MEDIA76/arcane/issues) on GitHub for reporting bugs is always appreciated.\n\n*License*: Copyright 2017-2026 [Joshua Britt](https://github.com/capachow) under the [MIT](LICENSE.md).\n\n---\n\n### 13. The Meaning of Arcane\n\nThe word *arcane* refers to mysterious knowledge, secrets understood by only a few.\n\nIn an era of endless configuration and complexity, simplicity has become that secret. We have largely forgotten that the web was meant to be crafted, not configured. Arcane is a return to that lost art. It is a reminder that real mastery does not require complexity. It requires deep understanding.\n\n\u003e Now go have fun and develop something you are proud of, but keep it **Arcane**.","funding_links":["https://github.com/sponsors/capachow"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapachow%2Farcane","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcapachow%2Farcane","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapachow%2Farcane/lists"}