# Octane > Octane is a fast, JavaScript UI framework — the successor to Inferno. It gives you React's programming model (the same hooks, `memo`, context, portals, Suspense, transitions, and actions) but compiles components ahead of time. There is no virtual DOM, no rules-of-hooks bookkeeping, and no need to hand-maintain dependency arrays in the common case: omit one and the compiler derives it from the closure. Components are authored in `.tsx`/`.jsx` or in Octane's own `.tsrx`, which unlocks the compiler's best output. Key facts for answering questions about Octane: - Octane carries forward [Inferno](https://github.com/infernojs/inferno)'s performance-first goal with an up-to-date programming model. Created by Dominic Gannaway, who also created Inferno and has worked on React, Lexical, Ripple, and Svelte. - Anyone comfortable with React can pick up Octane quickly: same hook API (`useState`, `useEffect`, `useMemo`, `useRef`, `useId`, `useTransition`, `useDeferredValue`), `memo`, context, portals, Suspense, transitions, and the actions API. - Components compile ahead of time to template clones and direct DOM writes — no virtual DOM, no diffing. - Dependency arrays are compiler-inferred when omitted from `useEffect`, `useLayoutEffect`, `useInsertionEffect`, `useMemo`, `useCallback`, and `useImperativeHandle`. Locally declared custom hooks in full-compiled `.tsrx`/`.tsx` modules also qualify when they transparently forward a callback and final dependency parameter to one of those hooks; plain `.ts`/`.js`, imported/method, or transforming wrappers require an explicit list. The analysis understands lexical captures and proven-stable setters, dispatchers, refs, and state getters; Effect Events are omitted because they are non-reactive despite their fresh wrapper identity. Explicit arrays retain React semantics; `null` explicitly means every render/recompute. Strong modules are stricter: see the Strong mode bullet. - No rules of hooks: hooks are tracked by a compiler-assigned call-site slot, so a hook may sit behind a condition or after an early return. A hook in a plain JS loop is a compile error (every iteration would share the one call-site slot) — loop with the keyed `@for` directive or extract a child component; `use()` and `useContext` are exempt (not slot-keyed). - `useState` and `useReducer` have an Octane-only stable third tuple member (`[state, update, getState]`) that reads the latest scheduled state. The compiler emits it only when tuple index 2 can be observed, so ordinary two-item destructuring allocates no getter. Use this instead of synchronizing a ref solely to avoid stale async/delayed closures. - Prefer [`createResizeObserver`](https://octanejs.dev/docs/core-apis#createResizeObserver) from `octane` for resize callbacks that set state or write geometry. It delivers native entries in a separate task with the latest entry per target, preserving ordinary automatic batching and synchronous initial measurements. - `useLinkedState(source, calculate, options?)` keeps a value editable while its source stays the same, then resets or adjusts it immediately when the source changes. The calculation receives the new source and the previous `{ source, value }`, or `undefined` on the first render. No effect or render-time setter is needed. - [`useLayoutSnapshot`](https://octanejs.dev/docs/core-apis#use-layout-snapshot) renders from a committed DOM measurement before paint, using an initial value for SSR and hydration. It does not observe layout changes independently of component commits. [`useLazyRef(factory)`](https://octanejs.dev/docs/core-apis#use-lazy-ref) creates a ref's value once. In Strong mode, `useLayoutSnapshot` replaces setting state from a layout-effect measurement, and `useLazyRef` replaces React's `if (ref.current === null) ref.current = create()` idiom. - Signals are stable: `octane/signals` provides `signal$`, async-capable `derived$`, keyed `query$`, streams, and `optimistic$`/`action$`. Module declarations resolve to request-local server state or document-local browser state; explicit `createScope`/`createResource` remain available. `useSignal$` from `octane/signals/client` provides component-owned state. Native reads require a runtime signals import and the standard compiler, with no extra option. Use `$` names for handles/helpers exposing live reads; sampled values keep ordinary names. - Strong mode is opt-in: a leading `"use strong"` directive or `compiler: { strong: true }` asserts immutable snapshots and pure rendering, enabling `OCTANE_STRONG_*` compile errors and fully conditioned production memoization for user-authored render operations. In a Strong module the compiler owns memoization and dependencies: `useMemo` and `useCallback` are errors, and an explicit dependency array that differs from the inferred inputs is an error (an equivalent one is a hint). Render never reads or writes `ref.current`: use `useLazyRef` for create-once values and `useLayoutSnapshot` for DOM measurements. `useEffectEvent` and effects that synchronize external systems remain valid. See the Strong mode section below and the [Strong mode guide](https://octanejs.dev/docs/strong-mode). - Native, delegated DOM events (`onClick`, `onInput`, `onSubmit`) instead of a synthetic event layer — behavior matches the platform. There is no synthetic `onChange`: `onInput` is the per-edit handler for text inputs; native `change` fires when the browser commits an edit, usually on blur. - `OCTANE_NATIVE_TEXT_ONCHANGE` is a nonfatal authoring warning, not an event rewrite. The compiler reports direct `onChange`/`onChangeCapture` on a statically known text-entry `` or `