Annus Mirabilis · Interactive critical edition in preparation

Opposite pulses and two energy ledgers

Describe the same balanced emission in two frames.

An executable model

Two ledgers and opposite pulses

Static worked example

Model note
  • Light complex energy (moving system) (lightComplexEnergyMoving): Host calculation, by the site's own reference code. Computed in massEnergy.movingBalanceLight.
  • Emitted energy (object rest frame) (emittedEnergyRestFrame): Host calculation, by the site's own reference code. Computed in massEnergy.restBalanceLight.
  • Body energy before emission (stationary system) (bodyEnergyRestBefore): Host calculation, by the site's own reference code. Computed in massEnergy.restBodyBefore.
  • Body energy after emission (stationary system) (bodyEnergyRestAfter): Host calculation, by the site's own reference code. Computed in massEnergy.restBodyAfter.
  • Body energy before emission (moving system) (bodyEnergyMovingBefore): Host calculation, by the site's own reference code. Computed in massEnergy.movingBodyBefore.
  • Body energy after emission (moving system) (bodyEnergyMovingAfter): Host calculation, by the site's own reference code. Computed in massEnergy.movingBodyAfter.
  • Body kinetic energy difference (moving system) (kineticEnergyDifference): Host calculation, by the site's own reference code. Computed in massEnergy.kineticEnergyDifference.
  • Additive energy constant (additiveEnergyConstant): Host calculation, by the site's own reference code. Computed in massEnergy.additiveEnergyConstant.
  • Computed from the settings last applied (settings revision 1, result 1).
  • Not modeled: recoil from asymmetric emission; finite pulse duration and shape; the emission mechanism; radiation pressure on the body during emission; gravity; the quantum nature of light; the body's absolute rest energy (kept symbolic).

Predict before the numbers

If the body emits the two opposite pulses at an angle φ = 60° rather than along the direction of motion (φ = 0°), what happens to the total energy of the two light pulses measured by the moving observer?

Three relations the model could have

The result appears when you choose, say you have one in mind, or skip.

Try
Experiment settings emitted energy, the premise, how internal energy is written, notation, a link to these settings
The additive constant C
Internal energies written as
Notation

Worked example: a body emits 1 L of light in its rest frame; seen from a frame moving at 0.6c the two pulses carry 1.25 L together, and the body's kinetic energy falls by 0.25 L.

Seen from a frame moving at v = 0.6c

The body sends out two equal pulses in opposite directions, at φ = 0° to the direction of motion.

v = 0.6cbodypulse 1: 0.25 Lpulse 2: 1 L

The two energy accounts

Each line in units of the emitted energy L, for the accepted settings: v = 0.6c, φ = 0°. The body sends out two equal halves, L/2 each, in its own frame; the moving frame sees them unequal.
Line of the accountRest frame (K₀)Moving frame (k)
Body's energy before emissionE₀H₀
Light sent out1 L1.25 L
…of which pulse 1L/20.25 L
…of which pulse 2L/21 L
…the two pulses togetherL1.25 L
Body's energy after emissionE₁H₁
The account as an equationE₀ − E₁ = L; H₀ − H₁ = 1/√(1 − v²/V²)·L

Subtracting one account from the other

(H₀ − E₀) − (H₁ − E₁) = L(1/√(1 − v²/V²) − 1)

Drop in energy of motion: 0.25 L

The body's internal energies at rest cancel.

Show the code

The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.

evaluatePulseEnergies · src/physics/reference/massEnergy.ts · this site’s source, as built · sha256:eeb7552ef2676c312d9ed38a3601b7b3e1ed2387493ddaf20fd923234c7546de

This function computes the listed outputs when it runs.

In words

Seen from the moving frame, each of the two pulses carries half the emitted energy, times the Lorentz factor, times one minus or one plus the frame speed times the cosine of the emission angle. The angle cancels in the sum, which is the Lorentz factor times the emitted energy.

Implementation

/**
 * Kernel function: evaluates the moving-frame pulse energies and their angle-invariant sum (Paper 4, §1 & Paper 3, §8).
 * Pulse 1: (L/2) * gamma * (1 - beta * cos(phi))
 * Pulse 2: (L/2) * gamma * (1 + beta * cos(phi))
 * Sum: gamma * L
 */
export function evaluatePulseEnergies(
  emittedEnergyRestFrame: number,
  frameSpeed: number,
  emissionAngleRad: number,
): Readonly<{
  lorentzFactor: number;
  pulse1Moving: number;
  pulse2Moving: number;
  pulseSumMoving: number;
  pulseEnergyRatio: number;
  dopplerFrequencyRatio: number;
}> {
  const g = 1 / Math.sqrt(1 - frameSpeed * frameSpeed);
  const halfL = emittedEnergyRestFrame / 2;
  const cosPhi = Math.cos(emissionAngleRad);
  const factor1 = 1 - frameSpeed * cosPhi;
  const factor2 = 1 + frameSpeed * cosPhi;
  const p1 = halfL * g * factor1;
  const p2 = halfL * g * factor2;
  const sum = g * emittedEnergyRestFrame;
  const ratio = factor1 / factor2;
  return Object.freeze({
    lorentzFactor: g,
    pulse1Moving: p1,
    pulse2Moving: p2,
    pulseSumMoving: sum,
    pulseEnergyRatio: ratio,
    dopplerFrequencyRatio: ratio,
  });
}

The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.

evaluateLedgers · src/physics/reference/massEnergy.ts · this site’s source, as built · sha256:ad34802170ca8f200c091d17119d686c02b7a4beaf02d073f1722ac74965eae4

This function computes the listed outputs when it runs.

In words

In the frame where the body rests, it loses exactly the energy it emits. In the moving frame it loses the Lorentz factor times that energy. The function returns both balances, and if it is given an initial body energy it first seeds the ledger with it.

Implementation

/**
 * Kernel function: evaluates the rest-frame and moving-frame energy balances (Paper 4, §1).
 * Rest frame balance: E0 - E1 = L
 * Moving frame balance: H0 - H1 = gamma * L
 */
export function evaluateLedgers(
  emittedEnergyRestFrame: number,
  frameSpeed: number,
  _emissionAngleRad: number,
  initialBodyEnergy?: MassEnergyLedgerSeed,
): Readonly<{
  restBalanceLight: number;
  movingBalanceLight: number;
  lorentzFactor: number;
}> {
  if (initialBodyEnergy !== undefined) {
    initializeMassEnergyLedger({ restEnergyBefore: initialBodyEnergy });
  }
  const g = 1 / Math.sqrt(1 - frameSpeed * frameSpeed);
  return Object.freeze({
    restBalanceLight: emittedEnergyRestFrame,
    movingBalanceLight: g * emittedEnergyRestFrame,
    lorentzFactor: g,
  });
}

The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.

evaluateSubtraction · src/physics/reference/massEnergy.ts · this site’s source, as built · sha256:98436f159f767fc6824c6c3c79b8716f767c1e762857e1836ecef2058d24f207

This function computes the listed outputs when it runs.

In words

Subtract the rest-frame balance from the moving-frame balance: the emitted energy times the Lorentz factor minus one. If the premise holds that the additive constant does not change during the emission, that difference is the drop in the body's kinetic energy; with the premise set aside, no kinetic difference is returned. The Lorentz factor minus one is computed so that it does not round to zero at walking speeds, and an observer speed that is not finite and below the speed of light is refused.

Implementation

/**
 * Kernel function: evaluates the subtraction move (H0 - E0) - (H1 - E1) and the resulting kinetic energy difference (Paper 4, §1).
 * Subtraction: (H0 - E0) - (H1 - E1) = L * (gamma - 1)
 * If premise === "unchanged": K0 - K1 = L * (gamma - 1)
 */
export function evaluateSubtraction(
  emittedEnergyRestFrame: number,
  frameSpeed: number,
  _emissionAngleRad: number,
  premise: Me01Premise = "unchanged",
): Readonly<{
  subtractionValue: number;
  lorentzFactor: number;
  kineticDifference: number | null;
  premise: Me01Premise;
}> {
  const g = 1 / Math.sqrt(1 - frameSpeed * frameSpeed);
  // Reuse the cancellation-free owner: gamma - 1 rounds to zero at walking speeds.
  const difference = gammaMinusOne(frameSpeed);
  if (difference.status !== "value") {
    throw new RangeError("Subtraction requires a finite subluminal observer speed.");
  }
  const sub = emittedEnergyRestFrame * difference.value;
  return Object.freeze({
    subtractionValue: sub,
    lorentzFactor: g,
    kineticDifference: premise === "unchanged" ? sub : null,
    premise,
  });
}

The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.

initializeMassEnergyLedger · src/physics/reference/massEnergy.ts · this site’s source, as built · sha256:35f202a64ce0a1738e335423433623920b3e1c01fb8fa0707355cfd4779cbd0d

This function computes the listed outputs when it runs.

In words

Before and after the emission, in each of the two frames, the body has an energy nobody has measured. This function names all four of them, E0 and E1 in the rest frame and H0 and H1 in the moving frame, and returns each as a symbol rather than a value. Naming them is what lets the subtraction remove them.

Implementation

/**
 * Validates and initializes the mass-energy ledger.
 *
 * Enforces the non-circularity doctrine (Paper 4 / AGENTS.md):
 * The mass-energy ledger must NEVER initialise a body's energy with Mc^2 or gamma Mc^2.
 * Rest energy and moving body energy on the historical route must remain symbolic (E₀, H₀).
 * Any attempt to seed the ledger with Mc^2 or gamma Mc^2 is rejected with an Error.
 */
export function initializeMassEnergyLedger(
  seed?: MassEnergyLedgerInit,
): InitializedMassEnergyLedger {
  const isNumericValue = (val: unknown): boolean => {
    if (val === undefined || val === null) return false;
    if (typeof val === "number" && Number.isFinite(val)) return true;
    if (typeof val === "string") {
      const trimmed = val.trim();
      if (trimmed !== "" && !Number.isNaN(Number(trimmed))) return true;
    }
    if (typeof val === "object") {
      const rec = val as Record<string, unknown>;
      if (typeof rec.value === "number" && Number.isFinite(rec.value)) return true;
      if (rec.kind === "numeric" || rec.kind === "value") return true;
      if (typeof rec.numericFrom === "string") return true;
    }
    return false;
  };

  const isCircular = (val: unknown): boolean => {
    if (val === undefined || val === null) return false;
    if (typeof val === "string") {
      const lower = val.toLowerCase().replace(/[\s_*^·×-]/g, "");
      if (
        lower.includes("mc2") ||
        lower.includes("mc²") ||
        lower.includes("gammamc") ||
        lower.includes("γmc") ||
        lower.includes("mc^2")
      ) {
        return true;
      }
    }
    if (typeof val === "object") {
      const rec = val as Record<string, unknown>;
      if (rec.numericFrom === "mc2" || rec.numericFrom === "gamma-mc2") return true;
      if (typeof rec.formula === "string" && isCircular(rec.formula)) return true;
      if (typeof rec.id === "string" && isCircular(rec.id)) return true;
      if (typeof rec.kind === "string" && isCircular(rec.kind)) return true;
      if (typeof rec.expr === "string" && isCircular(rec.expr)) return true;
    }
    return false;
  };

  if (isCircular(seed?.restEnergyBefore) || isCircular(seed?.movingEnergyBefore)) {
    throw new MassEnergyError(
      "absolute-energy-not-admitted",
      "Circularity violation: the mass-energy ledger must NEVER initialise a body's energy with Mc^2 or gamma Mc^2.",
    );
  }

  if (seed?.historicalMode !== false) {
    if (isNumericValue(seed?.restEnergyBefore) || isNumericValue(seed?.movingEnergyBefore)) {
      throw new MassEnergyError(
        "absolute-energy-not-admitted",
        "Supplying a numeric absolute rest energy in the historical model is rejected. Rest and moving energies must remain symbolic.",
      );
    }
  }

  return Object.freeze({
    restBodyBefore: asSymbolic(
      "bodyEnergyRestBefore",
      "J",
      "rest-body-energy-before",
      "massEnergy.restBodyBefore",
      "E₀",
    ),
    restBodyAfter: asSymbolic(
      "bodyEnergyRestAfter",
      "J",
      "rest-body-energy-after",
      "massEnergy.restBodyAfter",
      "E₁",
    ),
    movingBodyBefore: asSymbolic(
      "bodyEnergyMovingBefore",
      "J",
      "moving-body-energy-before",
      "massEnergy.movingBodyBefore",
      "H₀",
    ),
    movingBodyAfter: asSymbolic(
      "bodyEnergyMovingAfter",
      "J",
      "moving-body-energy-after",
      "massEnergy.movingBodyAfter",
      "H₁",
    ),
  });
}

Not modeled in this ideal reference calculation:

recoil from asymmetric emission · finite pulse duration and shape · the emission mechanism · radiation pressure on the body during emission · gravity · the quantum nature of light · the body's absolute rest energy (kept symbolic)

Two equal flashes of light leave a body at rest in opposite directions. Seen by someone moving past, the flashes carry more energy than they do for the body, and the extra can only come from the body's energy of motion, which falls as if the body had lost mass.

The mass–energy paper imports one result from §8 of the relativity paper: light of energy l, seen from a frame moving at v along x, has energy l* = l(1 − (v/V) cos φ)/√(1 − (v/V)²), where φ is the angle between the light's direction and the x-axis. A body at rest in (x, y, z) sends out light of energy L/2 at the angle φ and an equal amount the opposite way, and stays at rest. The energy principle must hold in both frames: in the rest frame E₀ − E₁ = L, and in the moving one H₀ − H₁ = γL, writing γ for 1/√(1 − (v/V)²), because the two direction factors, 1 − (v/V) cos φ and 1 + (v/V) cos φ, add to 2. The body's energies E and H stay symbolic, and the lab never gives them values. Subtracting the two balances removes them: (H₀ − E₀) − (H₁ − E₁) = L{1/√(1 − (v/V)²) − 1}. Each H − E is the body's kinetic energy K in the moving frame plus a constant C, and C does not change during the emission, so K₀ − K₁ = L{1/√(1 − (v/V)²) − 1}. At the lab's default, L = 1 J and v = 0.6c, the moving observer counts 1.25 J of light, and the body's kinetic energy falls by 0.25 J whatever the angle. Drop the premise that C is unchanged and the difference is underdetermined, and the lab says so. To lowest order the drop is (L/V²)(v²/2), the kinetic energy of a mass L/V², and the paper concludes that a body giving off energy L as radiation loses mass L/V².

Modern qualifications

The paper, received on 27 September 1905, writes the factor in full as 1/√(1 − v²/V²), V for the speed of light, L for the emitted energy and l* for the transformed light energy. It cites §8 of the June paper for that transformation and notes in a footnote that the constancy of the speed of light used there is contained in Maxwell's equations. It states the result as L/V², and in cgs units as a mass change of L/9 · 1020 grams for L ergs, and suggests that radium salts might test it. The mass statement rests on the lowest-order term in v/V and on the source premise that C is unchanged. Planck gave a more general treatment in 1907, and Ives argued in 1952 that the 1905 argument was circular, a reading others have disputed. The paper itself says only that the mass of a body is a measure of its energy content.

The explanation

Full explanation

Change the emission angle and compare the individual pulse energies with their sum. Then inspect the subtraction of the two energy balances and the role of the offset premise.

Show every step of the investigation

Follow the moving pulses, their angle-free sum, both balances, the subtraction, and the kinetic-energy interpretation. The light-energy transformation is an imported premise; a mass-energy formula is not installed as the starting answer.

An explanatory model, not an observation of nature. This embed starts from the laboratory’s worked defaults, not a saved run. Presentation options change the surrounding guide, never the numerical inputs.