@@ -207,7 +222,66 @@ const { run, execResultPre, execResultPost } = useStandardPrecompileRun(
```
-The `useStandardPrecompileRun` helper covers the common EthereumJS pre/post hardfork comparison. For custom execution (different library, custom precompile, etc.), provide your own `run` function and `#result` slot — see [Available E-Components](/contributing/available-e-components) for the full API reference.
+The `useStandardPrecompileRun` helper covers the common EthereumJS pre/post hardfork comparison. For custom execution, provide your own `run` function and `#result` slot.
+
+**Reference:** [EIP-7951](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-7951/MyC.vue)
+
+#### Bytecode / opcode explorations
+
+For explorations that step through raw EVM bytecode, use the Bytecode Stepper E-Component. The exploration creates and owns the EVM instance:
+
+```typescript
+// config.ts
+import type { BytecodeStepperConfig } from '@/eComponents/bytecodeStepperEC/types'
+
+export const config: BytecodeStepperConfig = {
+ explorationId: 'eip-XXXX',
+ defaultExample: 'basic',
+}
+```
+
+```vue
+
+
+
+
+
+```
+
+Example presets use `values[0]` as unprefixed hex bytecode. For programmatic bytecode construction, add helper modules in your exploration folder.
+
+**Reference:** [EIP-8024](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-8024/MyC.vue)
+
+See [Available E-Components](/contributing/available-e-components) for the full API reference of each E-Component.
+
+### Extending When the Core E-Component Is Not Enough
+
+E-Components cover repeatable patterns. Explorations often need additional teaching UI, domain helpers, or custom visualization on top. Keep these additions in your **exploration folder** unless a second exploration needs the same thing.
+
+| Need | Approach |
+| ----------------------------------------------------- | ------------------------------------------------------------------------------------- |
+| Custom result display | Use the E-Component's scoped slot (e.g. `#result`) |
+| Additional panel or region | Use a layout slot (e.g. `#below`) and render a companion `.vue` component inside it |
+| React to live runtime state | Use the E-Component's inject context from a companion component mounted inside a slot |
+| Bytecode builders, domain decode logic, test fixtures | Add `.ts` modules in the exploration folder |
+
+::: warning Slots and inject
+Provide/inject only works for **descendants**. Companion components must be mounted inside the E-Component's slot tree — not as siblings placed next to the E-Component in `MyC.vue`.
+:::
+
+Keep `MyC.vue` thin: config, library wiring, E-Component tag, and slot content. Push logic into testable modules. See [E-Components — Integration Contract](/contributing/e-components#integration-contract) for the full model.
## Step 5: Register in the Registry
@@ -232,7 +306,7 @@ If your widget needs additional libraries, install them:
npm install some-library
```
-Import libraries only in your `MyC.vue` — never in shared code. This keeps each exploration's dependencies isolated via Vite's code splitting.
+Import libraries in your exploration folder (`MyC.vue`, `config.ts`, helpers) — not in shared E-Component code. This keeps each exploration's dependencies isolated via Vite's code splitting. E-Components accept library instances and callbacks as props instead.
If you need a library that isn't in `package.json` yet, or need a customized version, see [Third-Party Libraries](/contributing/third-party-libraries).
@@ -247,9 +321,14 @@ Each exploration should have a `tests.spec.ts` file in its folder. Tests verify
- `info.ts` — correct `id`, `path`, `topic`, and `poweredBy`
- `examples.ts` — each example has the right number of values, valid hex data, and a non-empty title
+**E-Component explorations** should additionally test:
+
+- `config.ts` — `defaultExample` exists in examples; config fields match expectations
+- Execution integration — e.g. round-trip through `run` or `runBytecode` where applicable
+- Companion components — if present, test via optional props (avoid requiring full E-Component mount when a slimmer test suffices)
+
**Precompile explorations** should additionally test:
-- `config.ts` — `defaultExample` exists in examples, value field count and URL params match expectations
- `assembleData`/`parseData` — if defined, verify they produce correct output and are inverse operations
### Example: Custom Exploration Test
@@ -343,6 +422,7 @@ npm run build # verify production build
- [ ] Created `src/explorations/
/MyC.vue` with interactive widget
- [ ] Created `src/explorations//examples.ts` with example presets
- [ ] Created `src/explorations//tests.spec.ts` with unit tests
+- [ ] Created `config.ts` and any companion components/helpers (if using an E-Component with extensions)
- [ ] Added import and entry in `src/explorations/REGISTRY.ts`
- [ ] Installed library dependencies (if needed)
- [ ] All unit tests pass
diff --git a/docs/contributing/ai-assisted-development.md b/docs/contributing/ai-assisted-development.md
index 0899fda..6f90239 100644
--- a/docs/contributing/ai-assisted-development.md
+++ b/docs/contributing/ai-assisted-development.md
@@ -19,24 +19,28 @@ npm run dev
Before writing any code, instruct your agent to read the project documentation. The docs are compact and self-contained — an agent can absorb them in one pass:
-> *Read all files under `docs/` to understand the project structure, contribution guidelines, and component APIs. Then follow the step-by-step guide in "Adding an Exploration" to create a new exploration for EIP-XXXX.*
+> _Read all files under `docs/` to understand the project structure, contribution guidelines, and component APIs. Then follow the step-by-step guide in "Adding an Exploration" to create a new exploration for EIP-XXXX._
Key pages the agent should internalize:
-| Page | Why |
-|------|-----|
-| [Architecture](/guide/architecture) | Content model, taxonomies (topics, timeline, tags), design decisions |
-| [Adding an Exploration](/contributing/adding-an-exploration) | Step-by-step creation guide with field reference |
-| [Available E-Components](/contributing/available-e-components) | Reusable components that can save 80% of the work for precompile explorations |
-| [Styling & Design](/contributing/styling) | CSS variables, design system classes — avoid hardcoded colors |
-| [Code Conventions](/contributing/code-conventions) | Import order, naming, linting rules |
+| Page | Why |
+| -------------------------------------------------------------- | -------------------------------------------------------------------- |
+| [Architecture](/guide/architecture) | Content model, taxonomies (topics, timeline, tags), design decisions |
+| [E-Components](/contributing/e-components) | Integration model, extension points, composition |
+| [Adding an Exploration](/contributing/adding-an-exploration) | Step-by-step creation guide with field reference |
+| [Available E-Components](/contributing/available-e-components) | Ready-to-use building blocks — check here before building custom |
+| [Styling & Design](/contributing/styling) | CSS variables, design system classes — avoid hardcoded colors |
+| [Code Conventions](/contributing/code-conventions) | Import order, naming, linting rules |
### 3. Pick the Right Starting Point
-Not all explorations require the same effort. Help the agent choose:
+Not all explorations require the same effort. Help the agent choose in this order:
-- **Precompile exploration?** → Use the Precompile Interface E-Component. The agent only needs to define a config, examples, and a result slot. This can be done in under 50 lines of widget code.
-- **Custom widget?** → The agent builds from scratch using shared UI components. More freedom, more code, but the `ExplorationC` wrapper still handles the chrome (title, intro, links).
+1. **Check [Available E-Components](/contributing/available-e-components) first.** If one matches, wire config, examples, and execution — often under 30 lines in `MyC.vue`.
+2. **Need more than the core E-Component provides?** Add exploration-local UI via slots or companion components. See [Extending When the Core E-Component Is Not Enough](/contributing/adding-an-exploration#extending-when-the-core-e-component-is-not-enough).
+3. **Nothing fits?** Build a custom widget with shared UI components and `ExplorationC`. More freedom, more code.
+
+For reference explorations by pattern: [EIP-7951](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-7951/MyC.vue) (precompile), [EIP-8024](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-8024/MyC.vue) (bytecode stepper with companion panel).
### 4. Iterate with the Dev Server Running
@@ -58,19 +62,17 @@ npx vitest run # unit tests
Give the agent the EIP number, a link to the spec, and a one-sentence summary of what the exploration should let users do. The more concrete the goal, the better the output:
-> *Create an exploration for EIP-7883 (ModExp gas cost increase). The widget should let users enter ModExp inputs (base, exponent, modulus) and compare gas costs before and after the change.*
+> _Create an exploration for EIP-7883 (ModExp gas cost increase). The widget should let users enter ModExp inputs (base, exponent, modulus) and compare gas costs before and after the change._
### Reference Existing Explorations
-Existing explorations are the best examples. Point the agent at a similar one:
+Existing explorations are the best examples. Point the agent at one with a similar pattern:
-> *Look at `src/explorations/eip-7951/` as a reference — this new exploration follows the same precompile interface pattern.*
+> _Look at `src/explorations/eip-7951/` for a precompile exploration, or `src/explorations/eip-8024/` for a bytecode stepper with a companion panel._
### Let the Agent Read Real Source Files
-Documentation describes the intended patterns, but the source files show the actual implementation. If the agent is unsure about something, tell it to read the relevant source:
-
-> *Read `src/eComponents/precompileInterfaceEC/types.ts` to understand the PrecompileConfig interface.*
+Documentation describes the intended patterns, but the source files show the actual implementation. If the agent is unsure about something, tell it to read the relevant source — for example the config type in `src/eComponents/EC/types.ts`, or an existing exploration's `MyC.vue` and `config.ts`.
### Ask for Incremental Steps
@@ -78,9 +80,10 @@ Large prompts that ask for everything at once tend to produce lower-quality resu
1. "Create `info.ts` with the metadata"
2. "Create `examples.ts` with three example presets"
-3. "Create the widget in `MyC.vue`"
+3. "Create `config.ts` and wire `MyC.vue` (E-Component or custom widget)"
4. "Register in `REGISTRY.ts` and verify it builds"
5. "Add unit tests"
+6. "Add companion components or helpers if the E-Component core is not enough"
## Common Pitfalls
@@ -88,7 +91,7 @@ Large prompts that ask for everything at once tend to produce lower-quality resu
AI agents love to write `text-blue-600` or `bg-green-100`. The project uses a topic-aware color system via CSS variables — hardcoded colors will look wrong when the exploration's topic changes. Remind the agent:
-> *Use `e-text`, `e-result-box`, and the other `e-*` CSS classes instead of hardcoding Tailwind color utilities. Read the Styling & Design docs.*
+> _Use `e-text`, `e-result-box`, and the other `e-_` CSS classes instead of hardcoding Tailwind color utilities. Read the Styling & Design docs.\*
### Stale Patterns
@@ -98,7 +101,7 @@ If your agent's training data is older than the project, it may generate pattern
Agents sometimes fabricate component names or props that don't exist. If the output references a component you haven't seen before, have the agent verify it exists:
-> *Search the codebase for `ComponentName` before using it. If it doesn't exist, use the documented alternatives.*
+> _Search the codebase for `ComponentName` before using it. If it doesn't exist, use the documented alternatives._
### Skipping the Registry
@@ -108,6 +111,10 @@ The agent may create all the exploration files but forget to add the import to `
Agents may guess topic, timeline, or tag values. Remind them that topics and timeline entries are a fixed set — the agent should read `TOPICS.ts` and `TIMELINE.ts` to see the valid IDs. Tags come from the `Tag` enum in `TAGS.ts` and new ones can be proposed, but must follow the [tag rules](/guide/architecture#tags).
+### Extension UI Outside the Slot Tree
+
+When adding companion panels to an E-Component, agents often mount them as siblings next to the E-Component in `MyC.vue`. Provide/inject only works for **descendants** — extension UI must go inside an E-Component slot (e.g. `#below`, `#result`). See [E-Components — Extension Points](/contributing/e-components#extension-points).
+
## Cursor / IDE-Specific Tips
If you are using [Cursor](https://cursor.com/) or a similar AI-native IDE:
diff --git a/docs/contributing/available-e-components.md b/docs/contributing/available-e-components.md
index e534117..3d82539 100644
--- a/docs/contributing/available-e-components.md
+++ b/docs/contributing/available-e-components.md
@@ -1,6 +1,24 @@
# Available E-Components
-This page lists all E-Components that are ready to use in your explorations. For background on how E-Components work and how to create new ones, see [E-Components](/contributing/e-components).
+This page lists all E-Components that are ready to use in your explorations. For background on the integration model, extension points, and how to create new ones, see [E-Components](/contributing/e-components).
+
+Each E-Component section follows the same structure: what it does, how to wire it, its config type, and how to extend it when the core API is not enough.
+
+## Overview
+
+| E-Component | Folder | Primary use case | Reference exploration |
+| -------------------- | ----------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
+| Precompile Interface | `precompileInterfaceEC` | EVM precompile input, execution, and result display | [EIP-7951](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-7951/MyC.vue) |
+| Bytecode Stepper | `bytecodeStepperEC` | Raw bytecode disassembly, run/step/reset, stack/memory/gas | [EIP-8024](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-8024/MyC.vue) |
+
+### Extension Points at a Glance
+
+| E-Component | Scoped slots | Layout slots | Inject context |
+| -------------------- | ----------------------------- | ------------ | -------------------------- |
+| Precompile Interface | `#result` (with `{ result }`) | — | — |
+| Bytecode Stepper | — | `#below` | `BYTECODE_STEPPER_CONTEXT` |
+
+---
## Precompile Interface (`precompileInterfaceEC`)
@@ -23,8 +41,6 @@ src/eComponents/precompileInterfaceEC/
└── run.ts # EVM precompile execution utility + useStandardPrecompileRun
```
-**Used by:** [EIP-7951](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-7951/MyC.vue) (secp256r1), [EIP-7883](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-7883/MyC.vue) (ModExp gas cost)
-
### Basic Usage
A precompile exploration provides a config for input layout, a `run` function for execution, and a `#result` slot for visualization. For the standard EthereumJS pre/post hardfork comparison, use the `useStandardPrecompileRun` helper:
@@ -36,8 +52,8 @@ import { Hardfork } from '@ethereumjs/common'
import PrecompileInterfaceEC from '@/eComponents/precompileInterfaceEC/PrecompileInterfaceEC.vue'
import PrecompileInterfaceResultEC from '@/eComponents/precompileInterfaceEC/PrecompileInterfaceResultEC.vue'
import { useStandardPrecompileRun } from '@/eComponents/precompileInterfaceEC/run'
-import type { PrecompileConfig } from '@/eComponents/precompileInterfaceEC/types'
+import { config } from './config'
import { examples } from './examples'
import { INFO as exploration } from './info'
@@ -46,15 +62,6 @@ const { run, execResultPre, execResultPost } = useStandardPrecompileRun(
Hardfork.Osaka,
'0a',
)
-
-const config: PrecompileConfig = {
- explorationId: 'eip-XXXX',
- defaultExample: 'basic',
- values: [
- { title: 'Input A', urlParam: 'a', expectedLen: 32n },
- { title: 'Input B', urlParam: 'b', expectedLen: 32n },
- ],
-}
@@ -74,6 +81,21 @@ const config: PrecompileConfig = {
```
+Define the config in a separate `config.ts` file (keeps it testable):
+
+```typescript
+import type { PrecompileConfig } from '@/eComponents/precompileInterfaceEC/types'
+
+export const config: PrecompileConfig = {
+ explorationId: 'eip-XXXX',
+ defaultExample: 'basic',
+ values: [
+ { title: 'Input A', urlParam: 'a', expectedLen: 32n },
+ { title: 'Input B', urlParam: 'b', expectedLen: 32n },
+ ],
+}
+```
+
### Component Props
| Prop | Required | Description |
@@ -129,33 +151,7 @@ interface PrecompileValueDef {
### Custom Data Assembly
-By default, individual values are simply concatenated to form the raw hex data. For precompiles with non-trivial data formats (like ModExp, which has length prefixes), provide custom `assembleData` and `parseData` functions:
-
-```typescript
-const config: PrecompileConfig = {
- // ...
- values: [
- { title: 'Blen', expectedLen: 32n, initialHex: '00'.repeat(32), showInput: false },
- { title: 'Elen', expectedLen: 32n, initialHex: '00'.repeat(32), showInput: false },
- { title: 'Mlen', expectedLen: 32n, initialHex: '00'.repeat(32), showInput: false },
- { title: 'B', urlParam: 'b' },
- { title: 'E', urlParam: 'e' },
- { title: 'M', urlParam: 'm' },
- ],
- assembleData: (hexVals, byteLengths) =>
- toHex(byteLengths[3], 32 * 2) +
- toHex(byteLengths[4], 32 * 2) +
- toHex(byteLengths[5], 32 * 2) +
- padHex(hexVals[3]) +
- padHex(hexVals[4]) +
- padHex(hexVals[5]),
- parseData: (data, byteLengths) => {
- byteLengths[3] = hexToBigInt(`0x${data.substring(0, 64)}`)
- byteLengths[4] = hexToBigInt(`0x${data.substring(64, 128)}`)
- byteLengths[5] = hexToBigInt(`0x${data.substring(128, 192)}`)
- },
-}
-```
+By default, individual values are simply concatenated to form the raw hex data. For precompiles with non-trivial data formats (like ModExp, which has length prefixes), provide custom `assembleData` and `parseData` functions in your config — see the [EIP-7883 config](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-7883/config.ts) for a working example.
### Execution: `run` Prop and `#result` Slot
@@ -166,7 +162,7 @@ The E-Component separates input management from execution. The exploration provi
#### Standard: `useStandardPrecompileRun`
-For the common pre/post hardfork comparison using the EthereumJS EVM, use the provided helper:
+For the common pre/post hardfork comparison using the EthereumJS EVM:
```typescript
import { useStandardPrecompileRun } from '@/eComponents/precompileInterfaceEC/run'
@@ -182,44 +178,13 @@ This returns a `run` function ready to pass as a prop and two reactive refs for
#### Custom Execution
-For explorations that need a different execution mechanism (custom precompile, different library, etc.), define your own `run` function and result state:
+For explorations that need a different execution mechanism, define your own `run` function and result state. The `#result` slot template lives in the exploration's scope, so it naturally accesses your own refs and computed properties. You can use `ResultBoxUIC` or any other UI component in the slot.
-```vue
-
-
-
-
-
-
-
- {{ myResult }}
- Press enter or change input...
-
-
-
-
-
-```
-
-The `#result` slot template lives in the exploration's scope, so it naturally accesses your own refs and computed properties.
+---
## Bytecode Stepper (`bytecodeStepperEC`)
@@ -231,14 +196,14 @@ A stepping debugger for raw EVM bytecode. The exploration injects a configured `
src/eComponents/bytecodeStepperEC/
├── BytecodeStepperEC.vue # Main component
├── BytecodeStepperResultEC.vue # ExecResult summary
+├── bytecodeStepperContext.ts # Typed inject key for extension panels
├── useBytecodeStepper.ts # Composable: state machine + run/step/reset
├── disassemble.ts # Hex → instruction rows via getOpcodesForHF
├── runBytecode.ts # runCode orchestration + step event gate
+├── opcodeExplain.ts # Per-instruction explanations
└── types.ts # BytecodeStepperConfig and internal types
```
-**Used by:** [EIP-8024](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-8024/MyC.vue) (DUPN/SWAPN/EXCHANGE stack opcodes)
-
### Basic Usage
The exploration creates an EVM for the target hardfork and passes it to the component:
@@ -263,6 +228,19 @@ const evm = await createEVM({ common })
```
+Define the config in a separate `config.ts` file:
+
+```typescript
+import type { BytecodeStepperConfig } from '@/eComponents/bytecodeStepperEC/types'
+
+export const config: BytecodeStepperConfig = {
+ explorationId: 'eip-XXXX',
+ defaultExample: 'basic',
+}
+```
+
+Example presets use `values[0]` as unprefixed hex bytecode. For programmatic bytecode construction, add helper modules in your exploration folder (see [EIP-8024 bytecode.ts](https://github.com/feelyourprotocol/website/blob/main/src/explorations/eip-8024/bytecode.ts)).
+
### Component Props
| Prop | Required | Description |
@@ -294,10 +272,50 @@ interface BytecodeStepperConfig {
### Execution Modes
-| Action | Behavior |
-| --------- | ------------------------------------------------------------------------------ |
-| **Run** | Execute bytecode to completion; record all step snapshots |
-| **Step** | Advance one opcode (step mode is pre-armed when bytecode is valid) |
-| **Reset** | Clear execution state, re-arm stepping; bytecode input is preserved |
+| Action | Behavior |
+| --------- | ------------------------------------------------------------------- |
+| **Run** | Execute bytecode to completion; record all step snapshots |
+| **Step** | Advance one opcode (step mode is pre-armed when bytecode is valid) |
+| **Reset** | Clear execution state, re-arm stepping; bytecode input is preserved |
Valid bytecode automatically enters step mode paused before the first opcode, so the first **Step** click executes that opcode. Changing bytecode triggers a full reset and re-arms stepping.
+
+### Extending Beyond the Core API
+
+#### `#below` Slot
+
+Render exploration-local companion components below the stepper UI:
+
+```vue
+
+
+
+
+
+
+
+```
+
+#### `BYTECODE_STEPPER_CONTEXT` Inject
+
+Companion components can read live stepper state via Vue's provide/inject. Import the typed key from `bytecodeStepperContext.ts`:
+
+```typescript
+import { inject } from 'vue'
+
+import { BYTECODE_STEPPER_CONTEXT } from '@/eComponents/bytecodeStepperEC/bytecodeStepperContext'
+
+const stepper = inject(BYTECODE_STEPPER_CONTEXT, null)
+// stepper?.activeInstruction — current instruction row (or undefined)
+// stepper?.mode — 'idle' | 'stepping' | 'running' | 'finished' | 'error'
+// stepper?.bytecodeHex — current bytecode input
+// stepper?.example — selected example key
+```
+
+::: warning Mount inside the slot tree
+Provide/inject only works for **descendants** of the component that calls `provide`. Companion panels must be rendered inside the `#below` slot (or another slot on `BytecodeStepperEC`), not as a sibling placed next to it in `MyC.vue`.
+:::
+
+For unit testing, companion components can accept the same values as optional props instead of relying on inject — see existing exploration panel tests for the pattern.
+
+Place domain-specific helpers, builders, and teaching UI in your exploration folder. Promote to shared code only when a second exploration needs the same pattern.
diff --git a/docs/contributing/e-components.md b/docs/contributing/e-components.md
index 2311faa..acec78c 100644
--- a/docs/contributing/e-components.md
+++ b/docs/contributing/e-components.md
@@ -2,10 +2,46 @@
**E-Components** are reusable, Ethereum-specific components that encapsulate common patterns across explorations. They live in `src/eComponents/` and are designed to let you build new explorations quickly without duplicating logic.
-While the shared [UI components](/contributing/ui-components) (`src/eComponents/ui/`) provide generic building blocks like buttons and input fields, E-Components go a level higher: they package complete Ethereum-domain patterns — like a full precompile testing interface — into a single component with a clean configuration API.
+While the shared [UI components](/contributing/ui-components) (`src/eComponents/ui/`) provide generic building blocks like buttons and input fields, E-Components go a level higher: they package complete Ethereum-domain patterns — precompile testing interfaces, bytecode steppers, and more — into components with a clean configuration API.
For the list of ready-to-use E-Components, see [Available E-Components](/contributing/available-e-components).
+## Integration Contract
+
+Each E-Component follows a shared integration model. Understanding this contract helps you wire explorations consistently and know where to add custom behavior.
+
+| Concern | Where it lives | Pattern |
+| ---------------------------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
+| **Page chrome** | E-Component | Wraps `ExplorationC` (title, intro, examples, powered-by) |
+| **Variation between explorations** | `config.ts` in the exploration folder | Typed config object, testable separately |
+| **Library / execution ownership** | Exploration (`MyC.vue` and exploration-local modules) | Exploration creates EVM instances, `run` callbacks, or fork-specific setup; E-Component receives them as props |
+| **Domain-specific visualization** | Exploration | Via **slots** or **companion components** wired into the E-Component |
+| **Shared runtime state** | E-Component composable, optionally exposed via **provide/inject** | For panels that need live state without prop-drilling |
+
+### Standard Props
+
+Most E-Components accept a common set of props:
+
+| Prop | Description |
+| ------------- | ---------------------------------------------------------------------- |
+| `config` | Exploration-specific configuration (see the E-Component's config type) |
+| `examples` | Example presets from the exploration's `examples.ts` |
+| `exploration` | Metadata from the exploration's `info.ts` |
+
+Beyond these, E-Components accept props for **exploration-owned execution** — for example a `run` callback or a pre-configured EVM instance. E-Components do not import third-party libraries themselves; see [Third-Party Libraries](/contributing/third-party-libraries).
+
+### Extension Points
+
+E-Components deliberately cover **repeatable patterns**, not every pedagogical idea an exploration might need. When the core API is not enough, use the E-Component's extension hooks before wrapping or forking it:
+
+| Mechanism | Best for | Notes |
+| -------------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
+| **Scoped slots** | Custom UI at a specific render point inside the E-Component | Slot props pass data back to the exploration (e.g. execution results) |
+| **Named layout slots** | Additional panels or regions alongside the core UI | Mount exploration-local components inside the slot |
+| **Provide/inject context** | Companion panels that react to live runtime state | Injection only works for **descendants** — extension UI must be mounted inside the E-Component's slot tree, not as a sibling next to it |
+
+Keep exploration-specific teaching UI, helpers, and domain logic in the **exploration folder**. Promote code to a shared utility or E-Component only when a second exploration needs the same thing.
+
## How E-Components Work
Each E-Component is a self-contained folder in `src/eComponents/` with a consistent internal structure:
@@ -33,11 +69,27 @@ E-Component folders and files are post-fixed with **`EC`** (for E-Component):
The typical pattern is:
-1. Import the E-Component and its config type
-2. Define a config object describing your specific use case
-3. Render the component in your template with the config, examples, and exploration metadata
+1. Check [Available E-Components](/contributing/available-e-components) for a matching building block
+2. Define a `config.ts` describing your specific use case
+3. Wire execution in `MyC.vue` (EVM setup, `run` function, etc.)
+4. Render the E-Component with config, examples, and exploration metadata
+5. Add exploration-local UI via slots or companion components if needed
+
+This keeps `MyC.vue` short and declarative — often under 30 lines for straightforward cases. See [Adding an Exploration](/contributing/adding-an-exploration) for the full walkthrough.
+
+## Composing E-Components
+
+Today, each major E-Component wraps the full exploration shell (`ExplorationC`). That means **one primary E-Component per exploration** is the supported, documented path.
+
+Exploration-specific additions compose _on top of_ that E-Component via slots and inject — not by nesting two full E-Components side by side.
+
+As the project grows, we expect explorations that combine capabilities from multiple E-Components (for example, a precompile comparison alongside a bytecode walkthrough). To prepare for that:
+
+- **E-Component authors** should separate "page chrome" from "capability" where feasible — sub-components that can be used standalone, not only as part of the full wrapper
+- **Exploration authors** should keep custom additions local until a composition pattern is established project-wide
+- **Future direction:** an exploration-level layout that owns `ExplorationC` once and hosts multiple E-Component fragments
-This keeps your `MyC.vue` short and declarative — often under 30 lines.
+If you are designing an E-Component or an exploration that might need multi-component composition, [open an issue](https://github.com/feelyourprotocol/website/issues) to discuss the approach before investing in a one-off structure.
## Creating a New E-Component
@@ -48,7 +100,7 @@ If you spot a pattern shared across two or more explorations, it is a strong can
1. Create a folder in `src/eComponents/` following the naming convention: `EC/`
2. Define a `types.ts` with a configuration interface that captures the variation between use cases
3. Extract shared logic into a composable (`use.ts`)
-4. Build the component(s) with a clean, props-based API
+4. Build the component(s) following the [integration contract](#integration-contract) above
5. Document usage on the [Available E-Components](/contributing/available-e-components) page
### Design Principles
@@ -57,9 +109,11 @@ A good E-Component should:
- **Accept a config object** rather than many individual props — this keeps the consumer API minimal and easy to extend
- **Provide sensible defaults** where possible, so simple use cases stay simple
-- **Allow customization hooks** (callback functions in the config) for cases that need non-standard behavior
-- **Keep the consumer's `MyC.vue` short and declarative** — ideally just a config + a single component tag
-- **Encapsulate all state and logic** in a composable, keeping the Vue component focused on rendering
+- **Expose clear extension hooks** — slots and/or typed inject context for exploration-local additions
+- **Keep execution ownership in the exploration** — accept callbacks or library instances as props, never import third-party libraries directly
+- **Keep the consumer's `MyC.vue` short and declarative** — ideally config + wiring + a single component tag
+- **Encapsulate state and logic** in a composable, keeping the Vue component focused on rendering
+- **Favor composable fragments** over monolithic widgets — sub-components usable on their own make future multi-E-Component explorations easier
### Ideas for Future E-Components
diff --git a/docs/contributing/how-to-contribute.md b/docs/contributing/how-to-contribute.md
index e4ef704..4c887c1 100644
--- a/docs/contributing/how-to-contribute.md
+++ b/docs/contributing/how-to-contribute.md
@@ -27,6 +27,8 @@ Fix typos, add guides, clarify explanations. Documentation lives in the `docs/`
npm run docs:dev
```
+When a change affects the **structural base** (E-Components, contribution workflow, architecture), bump the patch version in `package.json` and add an entry to [Changelog](/changelog). New explorations alone do not require a version bump.
+
### Report Issues
Found a bug or have a suggestion? [Open an issue](https://github.com/feelyourprotocol/website/issues) on GitHub. Our issue templates will guide you through the relevant details.
@@ -71,21 +73,22 @@ npm run test:e2e # E2E tests
## What Goes Where
-| What you are working on | Where it lives |
-|------------------------|----------------|
-| A new exploration | `src/explorations//` |
-| Exploration metadata | `src/explorations//info.ts` |
-| Interactive widget | `src/explorations//MyC.vue` |
-| Example presets | `src/explorations//examples.ts` |
-| Exploration registry | `src/explorations/REGISTRY.ts` |
-| E-Components | `src/eComponents/EC/` |
-| Shared UI components | `src/eComponents/ui/` |
-| Unit tests | `src/views/__tests__/` (or co-located `__tests__/`) |
-| E2E tests | `cypress/e2e/` |
-| Documentation | `docs/` |
+| What you are working on | Where it lives |
+| ----------------------- | --------------------------------------------------- |
+| A new exploration | `src/explorations//` |
+| Exploration metadata | `src/explorations//info.ts` |
+| Interactive widget | `src/explorations//MyC.vue` |
+| Example presets | `src/explorations//examples.ts` |
+| Exploration registry | `src/explorations/REGISTRY.ts` |
+| E-Components | `src/eComponents/EC/` |
+| Shared UI components | `src/eComponents/ui/` |
+| Unit tests | `src/views/__tests__/` (or co-located `__tests__/`) |
+| E2E tests | `cypress/e2e/` |
+| Documentation | `docs/` |
## Further Reading
+- [Changelog](/changelog) — structural-base history (check after pulling `main`)
- [AI-Assisted Development](/contributing/ai-assisted-development) — best practices for building explorations with AI agents
- [Adding an Exploration](/contributing/adding-an-exploration) — step-by-step guide
- [Using E-Components](/contributing/e-components) — reusable Ethereum-specific components
diff --git a/docs/contributing/ui-components.md b/docs/contributing/ui-components.md
index e0f8982..a70a8e0 100644
--- a/docs/contributing/ui-components.md
+++ b/docs/contributing/ui-components.md
@@ -1,6 +1,6 @@
# UI Components
-The project provides a set of generic, reusable UI components that you can use in any exploration or E-Component. They live in `src/eComponents/ui/` and are already styled with the exploration design system — colors adapt automatically to the current topic.
+The project provides a set of generic, reusable UI components that you can use in any exploration or E-Component. They live in `src/eComponents/ui/` and are already styled with the exploration design system — colors adapt automatically to the current topic. For the `e-*` CSS classes used in the examples below, see [Styling & Design](/contributing/styling).
## Where UI Components Live
@@ -9,24 +9,23 @@ UI components are organized by scope:
```
src/eComponents/
├── ui/ # Shared across all E-Components and explorations
-│ ├── resultBox/ # Result display components
+│ ├── resultBox/
│ │ └── ResultBoxUIC.vue
│ ├── ExamplesUIC.vue
│ ├── HexDataInputUIC.vue
│ ├── ActionButtonUIC.vue
│ ├── ButtonUIC.vue
│ └── TooltipUIC.vue
-└── precompileInterfaceEC/
- └── ui/ # (future) Components specific to this E-Component
+└── EC/ # E-Component folders (optional local ui/ subfolder)
```
The placement rules:
-| Scope | Location | Example |
-|-------|----------|---------|
-| Used across multiple E-Components or explorations | `src/eComponents/ui/` | `ResultBoxUIC`, `ExamplesUIC` |
-| Specific to one E-Component | `src/eComponents//ui/` | (none yet) |
-| Specific to one exploration | `src/explorations//custom/ui/` | (none yet) |
+| Scope | Location | Example |
+| ------------------------------------------------- | ------------------------------ | ------------------------------------------ |
+| Used across multiple E-Components or explorations | `src/eComponents/ui/` | `ResultBoxUIC`, `ExamplesUIC` |
+| Specific to one E-Component | `src/eComponents/EC/ui/` | (none yet) |
+| Specific to one exploration | `src/explorations//` | Companion `.vue` files alongside `MyC.vue` |
## Available Components
@@ -38,11 +37,11 @@ Example selector dropdown built on [Headless UI Listbox](https://headlessui.dev/
```
-| Prop | Type | Description |
-|------|------|-------------|
-| `v-model` | `string` | Selected example key |
-| `examples` | `Examples` | Object mapping keys to `{ title, values }` |
-| `change` | `() => void` | Called when selection changes |
+| Prop | Type | Description |
+| ---------- | ------------ | ------------------------------------------ |
+| `v-model` | `string` | Selected example key |
+| `examples` | `Examples` | Object mapping keys to `{ title, values }` |
+| `change` | `() => void` | Called when selection changes |
### HexDataInputUIC
@@ -52,10 +51,10 @@ Hex data input textarea for raw byte input.
```
-| Prop | Type | Description |
-|------|------|-------------|
-| `v-model` | `string` | The hex data string |
-| `rows` | `number` | Textarea row count |
+| Prop | Type | Description |
+| ------------ | ------------ | ---------------------- |
+| `v-model` | `string` | The hex data string |
+| `rows` | `number` | Textarea row count |
| `formChange` | `() => void` | Called on input change |
### ResultBoxUIC
@@ -68,12 +67,12 @@ Result display box with a title label. Used for showing computation output. Has
```
-| Prop | Type | Description |
-|------|------|-------------|
-| `title` | `string` | Title label shown in the box |
-| `left` | `boolean` | Alignment: `true` for left, `false` for right |
-| `infoText` | `string?` | Placeholder text shown when no content is available |
-| `errorText` | `string?` | Error message (red) with a "Report on GitHub" hint |
+| Prop | Type | Description |
+| ----------- | ---------- | -------------------------------------------------------------- |
+| `title` | `string` | Title label shown in the box |
+| `left` | `boolean?` | Alignment: `true` for left, `false` for right (default: right) |
+| `infoText` | `string?` | Placeholder text shown when no content is available |
+| `errorText` | `string?` | Error message (red) with a "Report on GitHub" hint |
`errorText` takes precedence over `infoText`. Both render below the slot content, so conditionally pass them only when the slot is empty:
@@ -105,20 +104,25 @@ Async action button with loading state and tooltip. Disables itself and shows "L
```
-| Prop | Type | Description |
-|------|------|-------------|
-| `text` | `string` | Button label |
-| `tooltip` | `string` | Tooltip text on hover |
-| `onClick` | `() => Promise` | Async click handler |
+| Prop | Type | Description |
+| --------- | --------------------- | --------------------- |
+| `text` | `string` | Button label |
+| `tooltip` | `string` | Tooltip text on hover |
+| `onClick` | `() => Promise` | Async click handler |
### ButtonUIC
-Small icon button with tooltip. Used internally by `ExplorationC` for share and external-link icons.
+Small icon button with tooltip. Used internally by `ExplorationC` for share and external-link icons. Wrap it in a clickable element when you need button behavior — the component itself renders the icon only.
```vue
```
+| Prop | Type | Description |
+| --------- | ----------- | ------------------------------------------------------- |
+| `icon` | `Component` | Vue component for the icon (e.g. from `@heroicons/vue`) |
+| `tooltip` | `string?` | Tooltip text on hover |
+
### TooltipUIC
CSS tooltip wrapper. Used internally by `ButtonUIC` and `ActionButtonUIC`. You typically don't need this directly — use `ActionButtonUIC` or `ButtonUIC` instead.
@@ -128,6 +132,7 @@ CSS tooltip wrapper. Used internally by `ButtonUIC` and `ActionButtonUIC`. You t
Some UI components use [Headless UI](https://headlessui.dev/) (`@headlessui/vue`) — a set of completely unstyled, accessible UI primitives designed for Tailwind CSS. Headless UI handles keyboard navigation, focus management, and ARIA attributes while we control all styling via the exploration design system.
Currently used by:
+
- `ExamplesUIC` — uses the Headless UI **Listbox** component
As a contributor you don't need to interact with Headless UI directly — just use the UIC components as documented above.
@@ -137,7 +142,8 @@ As a contributor you don't need to interact with Headless UI directly — just u
All shared UI components use the `@/eComponents/ui/` path:
```typescript
+import ActionButtonUIC from '@/eComponents/ui/ActionButtonUIC.vue'
import ExamplesUIC from '@/eComponents/ui/ExamplesUIC.vue'
+import HexDataInputUIC from '@/eComponents/ui/HexDataInputUIC.vue'
import ResultBoxUIC from '@/eComponents/ui/resultBox/ResultBoxUIC.vue'
-import ActionButtonUIC from '@/eComponents/ui/ActionButtonUIC.vue'
```
diff --git a/docs/guide/architecture.md b/docs/guide/architecture.md
index 0598d4b..1071bc9 100644
--- a/docs/guide/architecture.md
+++ b/docs/guide/architecture.md
@@ -38,13 +38,13 @@ Topics are the high-level strategic pillars that group explorations by theme. Ea
**Topics are a static, curated set — they are not meant to be added as part of regular contributions.** The current topics are:
-| ID | Title | Description |
-|----|-------|-------------|
-| `scaling` | Scaling | Data availability, throughput, and L2 enablement |
-| `privacy` | Privacy | ZK-proofs, homomorphic encryption, private mempools |
-| `ux` | UX | Account abstraction, wallet infrastructure, signature schemes |
-| `security` | Security | Validator incentives, cryptographic agility, MEV mitigations |
-| `robustness` | Robustness | Gas cost accuracy, EVM semantics hardening, spec clarity |
+| ID | Title | Description |
+| ------------------ | ---------------- | ---------------------------------------------------------------------- |
+| `scaling` | Scaling | Data availability, throughput, and L2 enablement |
+| `privacy` | Privacy | ZK-proofs, homomorphic encryption, private mempools |
+| `ux` | UX | Account abstraction, wallet infrastructure, signature schemes |
+| `security` | Security | Validator incentives, cryptographic agility, MEV mitigations |
+| `robustness` | Robustness | Gas cost accuracy, EVM semantics hardening, spec clarity |
| `interoperability` | Interoperability | Cross-chain standards, bridge infrastructure, signature scheme support |
When adding an exploration, pick the topic that best reflects the primary concern of the protocol change.
@@ -61,45 +61,45 @@ Tags enrich navigation by adding broader Ethereum technical concepts, protocol-r
**Tags grow with contributions** — unlike topics and timeline, new tags can be proposed when adding an exploration. They must follow these rules:
-| Rule | Example |
-|------|---------|
-| Must be reusable beyond a single exploration | `EVM` ✅ — `EIP-7883` ❌ |
-| Short form preferred | `EVM` ✅ — `Ethereum Virtual Machine` ❌ |
-| No redundancy with existing tags | `Gas Costs` exists → don't add `Gas` |
-| When in doubt, choose the more generic concept | `Gas Costs` ✅ — `Gas Increases` ❌ |
+| Rule | Example |
+| ---------------------------------------------- | ---------------------------------------- |
+| Must be reusable beyond a single exploration | `EVM` ✅ — `EIP-7883` ❌ |
+| Short form preferred | `EVM` ✅ — `Ethereum Virtual Machine` ❌ |
+| No redundancy with existing tags | `Gas Costs` exists → don't add `Gas` |
+| When in doubt, choose the more generic concept | `Gas Costs` ✅ — `Gas Increases` ❌ |
**Format:** Enum keys use CamelCase (`GasCosts`), all-caps for abbreviations (`EVM`). Members must be sorted alphabetically (enforced by lint).
## E-Components
-**E-Components** are reusable Ethereum-specific components that encapsulate common patterns across explorations. They live in `src/eComponents/` and follow a naming convention: folder and component names are post-fixed with `EC`.
+**E-Components** are reusable Ethereum-specific components that encapsulate common exploration patterns. They live in `src/eComponents/` — one folder per pattern, with folder and component names post-fixed with `EC`.
-The first E-Component is `precompileInterfaceEC`, which provides a complete precompile exploration interface — input parsing, hardfork comparison, result display — as a single component backed by a composable:
+Each E-Component packages a recurring kind of interactive widget: page chrome (`ExplorationC`), example selection, domain-specific inputs, and shared state in a composable. The exploration wires it up via a typed `config.ts`, passes in execution (a `run` callback, an EVM instance, …), and adds exploration-local UI through slots or companion components when the core API is not enough.
```
-src/eComponents/precompileInterfaceEC/
-├── PrecompileInterfaceEC.vue # Full-featured precompile exploration template
-├── PrecompileInterfaceResultEC.vue # Result display (pre/post hardfork comparison)
-├── PrecompileValueInputEC.vue # Value input with byte length validation
-├── usePrecompileState.ts # Composable: all state and logic
-├── types.ts # PrecompileConfig and PrecompileValueDef interfaces
-└── run.ts # EVM precompile execution utility
+src/eComponents/EC/
+├── EC.vue # Main entry point
+├── types.ts # Config interface
+├── use.ts # Composable: state and logic
+└── … # Sub-components and utilities as needed
```
-Using the Precompile Interface E-Component, a precompile exploration widget can be as short as 30 lines — just a config object and a single component tag. See [Using E-Components](/contributing/e-components) for details.
+Examples in the codebase today include a **precompile testing interface** (`precompileInterfaceEC`) and a **bytecode stepper** (`bytecodeStepperEC`). More will follow as recurring patterns emerge — the set is meant to grow, not stay fixed on any one use case.
+
+For a typical E-Component-backed exploration, `MyC.vue` stays short: config, library setup, one component tag, and optional slot content. See [E-Components](/contributing/e-components) for the integration model and [Available E-Components](/contributing/available-e-components) for per-component API reference.
## UI Components
Generic UI components live in `src/eComponents/ui/` alongside the E-Components they serve. These are reusable building blocks available for any exploration or E-Component:
-| Component | Purpose |
-|-----------|---------|
-| `ExamplesUIC` | Example selector dropdown |
-| `HexDataInputUIC` | Hex data input textarea |
-| `ResultBoxUIC` | Result display box with title, info text, and error text |
-| `ActionButtonUIC` | Async action button with loading state and tooltip |
-| `ButtonUIC` | Icon button with tooltip |
-| `TooltipUIC` | CSS tooltip wrapper |
+| Component | Purpose |
+| ----------------- | -------------------------------------------------------- |
+| `ExamplesUIC` | Example selector dropdown |
+| `HexDataInputUIC` | Hex data input textarea |
+| `ResultBoxUIC` | Result display box with title, info text, and error text |
+| `ActionButtonUIC` | Async action button with loading state and tooltip |
+| `ButtonUIC` | Icon button with tooltip |
+| `TooltipUIC` | CSS tooltip wrapper |
Import them from `@/eComponents/ui/`:
@@ -133,7 +133,7 @@ Each exploration is a separate chunk that is loaded on demand. Users only downlo
```typescript
const componentModules = import.meta.glob('../explorations/*/MyC.vue')
const ExplorationComponent = defineAsyncComponent(
- componentModules[`../explorations/${explorationId}/MyC.vue`]
+ componentModules[`../explorations/${explorationId}/MyC.vue`],
)
```
diff --git a/docs/index.md b/docs/index.md
index 5322483..4986a7e 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -28,5 +28,5 @@ features:
---
::: warning Beta — Contributions Welcome!
-This project is in **beta**. Everything works, but the APIs of reusable components (E-Components, shared UI) are still evolving. That means contributions may require some manual coordination during review until the interfaces fully stabilize — we are happy to guide you through! The fastest way to get started is to [add a new exploration](/contributing/adding-an-exploration).
+This project is in **beta**. Everything works, but the APIs of reusable components (E-Components, shared UI) are still evolving. That means contributions may require some manual coordination during review until the interfaces fully stabilize — we are happy to guide you through! The fastest way to get started is to [add a new exploration](/contributing/adding-an-exploration). See the [changelog](/changelog) when the structural base moves forward.
:::
diff --git a/package.json b/package.json
index 523e02f..ca8dfe9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "feelyourprotocol.org",
- "version": "0.0.0",
+ "version": "0.1.1",
"private": true,
"type": "module",
"engines": {